On Mar 19, 2009, at 4:42 PM, Joshua Fox wrote:

> Because parallel bindings are also useful

Could you explain? I don't understand the justification for let in Lisp, when let* seems so much more useful.


As I mentioned, I like how Clojure's "let" works. I'm also fully on board with Rich's suggestion that before figuring out how to do something, we should first be sure it's important to do. I have not come up with any compelling reason for Clojure's let to provide more support for parallel binding than Mark Engleberg pointed out it provides already.

Since Rich's comment, I've done some reading about this and I saw two justifications for the behavior of Common Lisp's let:

[a] if one implements let in terms of lambda expressions, parallel binding produces one lambda expression while sequential binding produces nested lambdas, one per binding. Parallel binding implemented this way is simpler and uses less resources. In cases where you don't require the benefits of let*, use let because it's more efficient.

[b] when reading the expressions bound to names in a let expression in Common Lisp, you know that each expression stands alone. In particular you know that it has not been affected by any previous bindings in the same let.

I recall (perhaps imperfectly) that Rich has commented on [a] in the past with something like "nobody implements let that way and Clojure's sequential let is efficient".

Justification [b] sounds like it would be only a minor convenience for me, but does seem like a decent argument.

Regarding Clojure's "binding" operation, if we were not constrained by history, I think using a map for its bindings would be an improvement. The bindings it makes are different in several key ways from those made by the binding vectors used everywhere else in Clojure:

- the expressions are evaluated sequentially, but the binding is done in parallel - binding doesn't introduce new names, rather it must work with vars that already exist - the bindings it makes are thread-local and have dynamic scope rather than lexical scope
        - binding doesn't support destructuring

Using a map would serve as a clear marker that these bindings are not like anything else in Clojure. I think the case for this became stronger when Clojure changed to require vectors wherever "let-like bindings" were done (e.g., dotimes) some months ago. "binding" uses a vector, but its bindings are not "let-like".

--Steve

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to