2009-10-06 6 views
65
*compile-path**compile-path*の設定には違いがあることを理解しています。しかし、私は彼らがなぜ違うのかについて助けが必要です。

ClojureでのLetとBindingの比較

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

答えて

99

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

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

は考える:それが動作するため

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

bindingが(修飾名を使用することができます。

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

bindingは、実際にはローカル別名を持つVARをシャドウVarが、letのための動的結合を作成しますVar S)と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 -introducedバインディングは変更可能ではありません。 binding -introducedバインディングは、スレッドローカルで変更可能です:動的結合対

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参照してください。

+4

このプラスhttp://en.wikipedia.org/wiki/Scope_(programming)#Static_versus_dynamic_scopingは本当に私の理解を進歩させました。ありがとうございます! – Carl

+0

xはエラーをスローしないためには^:動的ヒントでバインドする必要があります。 – WeGi

8

bindingは、スレッドごとの地球環境

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

10

結合対のletのためのもう一つの構文上の差異:それらのいずれかが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 
+0

2番目の例を動作させるには、^:dynamicがxを0(動的に)に定義する必要があります。 – John

関連する問題