Perhaps you'd be more comfortable considering this equivalent syntax: (let [x 1] (let [y 2] (let [x (+ x y)] x)))
In principle, the multiple-binding let is transformed to this version and thus has identical semantics; in practice, the compiler does something more efficient but equivalent. That is, the innermost let is establishing a new scope, with a new binding x, whose value is computed by reference to the outer scope's x. The outer x remains unchanged, as you can see if you do something like (let [x 1] (let [y 2] (let [x (+ x y)] x)) x) This notion of nested scopes is present in many common languages, as is allowing nearby bindings to shadow more-distant bindings of the same name. And of course you can write something that "looks" imperative, like (let [x 1 x (inc x) x (* 2 x)] x) But because the general principle of immutability holds, anyone reading your code can easily "fold up" all the x-related expressions, into (let [x (* 2 (inc 1))] x). The same would *not* be true if real mutability were happening, as with a Java for loop, because statements could be executed multiple times with different values of x. Not so here: each expression is evaluated once, with a fixed value of x for each. Stylistically, it's often not very nice to rebind x a number of times; it's better to choose descriptive names for the intermediate steps. But there are certainly times occasions where using the same name can clarify meaning: for example, you're just "tidying up" x into a nicer form, or canonicalizing it in some way. On Aug 27, 2:37 am, Terje Dahl <te...@terjedahl.no> wrote: > I was surprised to discover that the following was possible: > > (let [ > x 1 > y 2 > x (+ x y) ] > x ) > > This runs and returns 3! > > This feels an awful lot like variables and procedural programming. > It is left up to the developer to not resetting a "variable" - by > convention - and if he reset the identifiers, he ends up with hard-to- > debug spagetti-code. > > I would have thought that the system would have protested when I > attempted to set 'x' to a new value! > Amit Rathore writes in "Clojure In Action" about : "[...] are locally > named values (they are like variables, but they can’t vary since > Clojure’s data-structures are immutable)" > > In combination underscore identifiers for throw-away return values, > one can in fact write a whole procedural program within the vector > parens of a let-statement! > > Perhaps this is something that should be changed in future versions of > the language?! -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en