6 ms·
For those of us who are unfamiliar with Lisps, can you expand on how they break referential transparency (and how Standard ML contrasts in that regard)?
by albedoa 3y ago
For those of us who are unfamiliar with Lisps, can you expand on how they break referential transparency (and how Standard ML contrasts in that regard)?
- medo-bear 3y agoHe is probably talking about namespaces. In common lisp, for example, (a a) calls a function 'a' on a variable 'a'. Lisp knows this because the first thing that comes after the left paren is a function
- convolvatron 3y agomore importantly there are functions (using scheme as an example) like set! and set-cdr! that mutate existing values and totally break referential transparency. this isn't just user facing - for example let* kind of depends on creating bindings up front so they work across clauses, and then mutating them afterwards
- amake 3y agoWhy does `let*` need to have mutation? It can be nested `let`s.
- convolvatron 3y agolet* permits expressions on the right refer to arbitrary other symbols bound by the let*. in particular it allows for construction of recursive lambdas that may not be linearlizable.
- amake 3y ago> let* permits expressions on the right refer to arbitrary other symbols bound by the let* In what language? I just checked Elisp, SBCL, and Guile, and they all error out if you refer to a variable not previously defined by a left-to-right traversal of the varlist: (let* ((a (+ b 1)) (b 1)) a) Edit: This doesn't work either: (let* ((a (lambda () (+ b 1))) (b 1)) (funcall a)) ; (funcall a) -> (a) for Schemes
- amake 3y agoAnyway, as far as I'm seeing it's perfectly possible to implement let* consistent with the above behavior as a macro without mutation as such: (define-macro (let* bindings &rest body) (if (null? bindings) `(progn ,@body) `(let (,(car bindings)) (let* ,(cdr bindings) ,@body))))
- tonyg 3y agoYou're thinking of letrec.
- amake 3y agoAh, that does look to be the case. I didn't know about that one. Signature (letrec BINDERS &rest BODY) Documentation Bind variables according to BINDERS then eval BODY. The value of the last form in BODY is returned. Each element of BINDERS is a list (SYMBOL VALUEFORM) that binds SYMBOL to the value of VALUEFORM. The main difference between this macro and let/let* is that all symbols are bound before any of the VALUEFORMs are evalled.
- medo-bear 3y agoLisp allows you to mutate, you can certainly write non-mutating code in lisp. Why do you think you need to use mutation with let*? let* is just a sequential let https://www.lispworks.com/documentation/lw70/CLHS/Body/s_let_l.htm https://www.lispworks.com/documentation/lw70/CLHS/Body/s_let...
- epgui 3y agoThey don’t. Or at least not inherently, if by “lisp” one is primarily referring to s-expressions.