Clojure允许多个具有相同名称的绑定

Tob*_*ede 12 clojure clojurescript

我试图理解我在Clojure中注意到的一些行为.

可以使用重复多次的相同绑定名创建let绑定:

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

(let [a 1 a 2 a 3] a)
; (= a 3)
Run Code Online (Sandbox Code Playgroud)

我明白让绑定进行评估,这一切都很有意义.

我对文档的理解是"用let创建的本地人不是变量.一旦创建,他们的价值观永远不会改变!"

上述语法是否实际更改了绑定的值?

这感觉它应该引发错误.

作为一种旁注:

有趣的是,您可以使用clojurescript输出上面的JS:

var a__36584 = 1, b__36585 = 2, a__36586 = b__36585;
var a__30671 = 1, a__30672 = 2, a__30673 = 3;
Run Code Online (Sandbox Code Playgroud)

在这里我们可以看到,这些值实际上都是不同的变量,它们指向了封面下发生的事情,但是一些澄清将非常有用.

ama*_*loy 24

(let [a 1, a 2] a)在功能上等同于(let [a 1] (let [a 2] a)),可能更容易理解.在后一种情况下,相对容易认识到您没有"修改"它的值a,而是引入一个以a不同值命名的新的无关变量.您可以通过以下方式查看此效果(let [a 1] (let [a 2] (println a)) a)- 它打印2,然后返回1,因为外部a永远不会更改,只会暂时隐藏.(let [a 1, a 2] a)只是引入一个名称a立即超出范围的值.当然,外部a是可用的,直到内部a有一个值,所以你可以做类似的事情(let [a 1, a (inc a)] a).


Vla*_*eev 10

let在clojure中的行为类似于let*Common Lisp,也就是说,它允许稍后使用的绑定.结合重新绑定,这可能很有用,例如当您需要以干净的方式删除某些数据层时:

(let [a some-vector, a (first a), a (:key a)] a)
Run Code Online (Sandbox Code Playgroud)

当然这不是错误.正如您所注意到的,这些绑定在内部影响不同的变量.这基本上是clojure词汇变量的不变性.由于这个词汇变量,重新绑定具有干净的语义(最后一个绑定"胜利"),并且没有理由不允许它.


mik*_*era 7

其他答案已经正确地指出let语法有效地为隐藏旧绑定的创建新绑定.

另外一个值得注意的要点是,当您知道某个值具有特定类型时,这对于优化Clojure代码非常有用,例如:

(let [d (double d)]
  ......)
Run Code Online (Sandbox Code Playgroud)

在let块中,d将被转换然后用作原始double,这可以大大加速许多数学运算.