2012-03-28 6 views
10

私はClojureで気づいたいくつかの動作を理解しようとしています。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; 

我々は値が何を指して、すべての実際の個別の変数、あることがわかりますカバーの下で起こっているが、いくつかの明確化は非常に役立つだろう。

答えて

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)のようなものでこの効果を見ることができます。外側のaは決して変更されず、一時的に隠されているので、2を出力してから1を返します。 (let [a 1, a 2] a)は、すぐに範囲外になるaという名前の値を導入するだけです。もちろん、外側のaは内部のaに値があるまで利用可能ですので、(let [a 1, a (inc a)] a)のようにすることができます。

8

letは、Common Lispのlet*のように動作します。つまり、後のバインディングを先に使用することができます。再結合と併せて、これは有用であり得る。いくつかのレイヤーをクリーンな方法で削除する必要がある場合:

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

もちろんこれは誤りではありません。ご存知のように、これらのバインディングは内部的に異なる変数に影響します。これは本質的にクロージャの語彙変数の不変性です。この字句的な変数のため、再バインドにはクリーンなセマンティクス(最後のバインディング "wins")があり、それを禁止する理由はありません。

6

他の回答は、let構文が効果的に新しいバインディングを作成し、古いバインディングを非表示にすることに注意しています。 LETブロック内

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

、Dは以下となります。注意すべき

一つの興味深い追加のポイントは、値が特定の型、例えばを持っていることを知ったとき、これはClojureのコードの最適化のために非常に有用にできることですキャストされ、その後、実質的に多くの数学的操作をスピードアップすることができるプリミティブダブルとして使用される。

関連する問題