12

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;

ここでは、値がすべて実際には別個の変数であることがわかります。これは、内部で何が起こっているかを示していますが、いくつかの説明が非常に役立ちます。

4

3 に答える 3

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)外側aは変更されず、一時的に非表示になるだけなので、2を出力してから1を返します。すぐに範囲外になる(let [a 1, a 2] a)という名前の値を導入するだけです。aもちろん、アウターaはインナーaに値が出るまで利用できるので、のようなことができます(let [a 1, a (inc a)] a)

于 2012-03-28T05:43:10.930 に答える
10

letclojurelet*では、Common Lispのように動作します。つまり、後のバインディングで前に使用できるようになります。再バインドと組み合わせて、これは、たとえば、データのいくつかのレイヤーをクリーンな方法で削除する必要がある場合に役立ちます。

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

そしてもちろん、これはエラーではありません。お気づきのように、これらのバインディングは内部的にさまざまな変数に影響を与えます。これは本質的に、clojureの字句変数の不変性です。この字句変数のために、再バインドにはクリーンなセマンティクスがあり(最後のバインドが「勝ち」)、それを禁止する理由はありません。

于 2012-03-28T05:42:24.613 に答える
7

他の回答は、let構文が古いバインディングを非表示にするaの新しいバインディングを効果的に作成することを正しく指摘しています。

注意すべき興味深い追加のポイントの1つは、値が特定のタイプを持つことがわかっている場合、これはClojureコードの最適化に非常に役立つ可能性があることです。

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

letブロック内で、dがキャストされ、プリミティブdoubleとして使用されます。これにより、多くの数学演算を大幅に高速化できます。

于 2012-03-28T10:57:27.473 に答える