Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure let allows multiple bindings with the same name

I am trying to understand some behaviour I have noticed in Clojure.

It is possible to create a let binding with the same binding-name repeated multiple times:

(let [a 1 a 2 a b] a)
; (= a 2)

(let [a 1 a 2 a 3] a)
; (= a 3)

I understand that let bindings are evaluated, and this all mostly makes sense.

My understanding from the docs is that "Locals created with let are not variables. Once created their values never change!"

Does the above syntax actually change the value of the bindings?

This feels like it should raise an error.

As a sort of side note:

Interestingly you can output the above as JS with clojurescript:

var a__36584 = 1, b__36585 = 2, a__36586 = b__36585;
var a__30671 = 1, a__30672 = 2, a__30673 = 3;

Here we can see that the values are all actually distinct variables, which points to what is happening under the covers, but some clarification would be very helpful.

like image 754
Toby Hede Avatar asked Mar 28 '12 04:03

Toby Hede


1 Answers

(let [a 1, a 2] a) is functionally equivalent to (let [a 1] (let [a 2] a)), which may be easier to understand. In the latter case, it is relatively easy to realize that you're not "modifying" the value of a, but introducing a new, unrelated variable named a with a different value. You can see the effect of this with something like (let [a 1] (let [a 2] (println a)) a) - it prints 2, and then returns 1, because the outer a is never changed, only temporarily hidden. (let [a 1, a 2] a) is simply introducing a value named a that immediately goes out of scope. Of course, the outer a is available until the inner a has a value, so you can do something like (let [a 1, a (inc a)] a).

like image 133
amalloy Avatar answered Sep 22 '22 06:09

amalloy