2012-10-17 39 views
8

我看看引用:http://clojure.org/vars#Vars%20and%20the%20Global%20Environmenthttp://clojuredocs.org/clojure_core/clojure.core/bindingclojure的動態變量和約束力的實用目的是什麼?

以及clojure and ^:dynamicClojure Dynamic Binding

我還是不明白,爲什麼有必要binding可言,因爲每個程序我已經寫了已經沒有它們,我可以找到方法以常規方式編寫示例 - 我覺得這更容易理解。有沒有項目/編程範例的例子可以使用這個?

例如......在動物說話例如,你可以得到類似的效果:

(def dog {:name "Dog" :sound "Woof"}) 
(def cat {:name "Cat" :sound "Meow"}) 

(defn speak [animal] 
    (str (:name animal) " says " (:sound animal)) 

(println (speak dog)) 
(println (speak cat)) 

沒有宏,沒有動態綁定...還是很乾淨的。

+0

Stuart Sierra在本博客文章中討論了Clojure中動態範圍的影響:http://stuartsierra.com/2013/03/29/perils-of-dynamic-scope –

回答

11

沒有嚴格需要他們:當你正確地觀察,你可以做任何你喜歡不binding,而事實上如果binding不存在,那麼你可以相對容易地重新實現它使用宏和Java的ThreadLocal s。

但是,綁定可以用作將動態上下文傳遞給函數而不需要顯式傳遞參數的方法。

當您編寫深度嵌套的高階函數並且不希望爲調用堆棧中的每個函數添加額外參數以便將某些值傳遞給嵌入深層的較低級函數時,它特別有用。

爲了擴大您的例子:

(def ^:dynamic *loud-noises* false) 

(defn speak [animal] 
    (str (:name animal) " says " 
      (let [sound (:sound animal)] 
      (if *loud-noises* (.toUpperCase sound) sound)))) 

(speak dog) 
=> "Dog says Woof" 

(binding [*loud-noises* true] 
    (speak dog)) 
=> "Dog says WOOF" 

注意我並不需要一個額外的參數添加到speak函數來得到不同的行爲。在這種情況下添加一個額外的參數將是微不足道的,但想象如果speak函數深埋在一個複雜的高階函數.....

不過,我認爲總體上最好的建議是避免動態綁定,除非你真的需要它。如果您可以添加顯式參數通常會更好:直接參數可以更輕鬆地測試和推理函數。

+1

爲什麼你偏好綁定到添加額外的參數到深層嵌套函數中的每個函數?如果我的函數調用'(說話狗)'和'(關門)',我怎麼知道'*吵鬧聲*'對應'speak'而不是'close-door'? – ToBeReplaced

+2

@ToBeReplaced我認爲你應該非常認真地考慮動態綁定的危險以及爲什麼使用它的設計應該被認真考慮。動態綁定確實允許上下文在你不控制中間的層之間傳輸。例如,clojure打印函數允許即使在第三方函數(不具有輸出流參數)的情況下使用輸出流時也能夠反彈。這也允許設置線程特定的行爲,但我懷疑動態綁定在大多數API中往往不利於有益。 –

+0

在下面看到我的帖子。 – zcaudate

1

只是跟進mikera的上面的例子..我可以看到你爲什麼會做一個不太語言表達,但因爲Clojure是如此表現,我寧願把它改寫......該loud-noise功能可以稍微再次改變,通過添加額外的參數來說話,達到同樣的效果......

(defn speak [animal & opts] 
    (let [sound (:sound animal) 
     sound (if (some #(= % :louder) opts) 
       (.toUpperCase sound) sound)] 
    (str (:name animal) " says " sound))) 


> (speak dog) 
;;=> "Dog says Woof" 
> (speak dog :louder) 
;;=> "Dog says WOOF" 

約束力只是一種破解了一個快速和骯髒的解決方案,如果你不能改變原有的代碼?

+4

你並不總是可以添加額外的參數 - 例如,如果你將函數傳遞給庫代碼,例如?或者如果函數是通用目的HOF,你不想用僅在特殊情況下使用的參數來污染? – mikera