web-dev-qa-db-ja.com

LetとClojureでのバインド

*compile-path*ありません。しかし、なぜそれらが異なるのかについて、助けが必要です。

letは、指定されたバインディングで新しいスコープを作成しますが、binding...?

68
Carl

letは、値のレキシカルスコープの不変エイリアスを作成します。 bindingは、一部のVarの動的スコープのバインディングを作成します。

動的バインディングとは、bindingフォーム内のコードと、そのコードが呼び出すローカルコード(ローカルレキシカルスコープにない場合でも)が新しいバインディングを認識することを意味します。

与えられた:

user> (def ^:dynamic x 0)
#'user/x

bindingは実際にはVarの動的バインディングを作成しますが、letはローカルエイリアスで変数をシャドウするだけです。

user> (binding [x 1] (var-get #'x))
1
user> (let [x 1] (var-get #'x))
0

bindingは修飾名を使用できます(Varsで動作するため)。letは次のことはできません。

user> (binding [user/x 1] (var-get #'x))
1
user> (let [user/x 1] (var-get #'x))
; Evaluation aborted.
;; Can't let qualified name: user/x

letで導入されたバインディングは変更できません。 binding-導入されたバインディングはスレッドローカルで変更可能です:

user> (binding [x 1] (set! x 2) x)
2
user> (let [x 1] (set! x 2) x)
; Evaluation aborted.
;; Invalid assignment target

字句バインディングと動的バインディング:

user> (defn foo [] (println x))
#'user/foo
user> (binding [x 1] (foo))
1
nil
user> (let [x 1] (foo))
0
nil

Varslet も参照してください。

106
Brian Carper

Letとbindingのもう1つの構文の違い:

バインディングの場合、初期値はすべて、varsにバインドされる前に評価されます。これは、前の「エイリアス」の値を後続の定義で使用できるletとは異なります。

user=>(let [x 1 y (+ x 1)] (println y))
2
nil

user=>(def y 0)
user=>(binding [x 1 y (+ x 1)] (println y))
1
nil
12
Marc

bindingは、スレッドごとのグローバル環境で名前に値をバインドします

あなたが述べたように、letは、前述のバインディングの新しいスコープを作成します。

9
Yuval Adam