Hacker News new | ask | show | jobs
by convolvatron 936 days ago
let* 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.
2 comments

> 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
Anyway, 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))))
You're thinking of letrec.
Ah, 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.