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

时间:2012-03-28 04:25:31

标签: clojure clojurescript

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

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

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

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

我明白让绑定得到评估,这一切都很有意义。

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

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

这感觉它应该引起错误。

作为一种旁注:

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

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

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

3 个答案:

答案 0 :(得分:22)

(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)之类的操作。

答案 1 :(得分:8)

clojure中的

let与Common Lisp中的let*行为相同,也就是说,它允许稍后使用的绑定。与重新结合相结合,这可能是有用的,例如当你需要以干净的方式删除某些数据层时:

(let [a some-vector, a (first a), a (:key a)] a)

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

答案 2 :(得分:6)

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

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

(let [d (double d)]
  ......)

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