2011-12-01 30 views
4

我今天開始使用Clojure,偶然發現可以在運行時動態更改函數的說法。 這聽起來很酷,所以我使用這個功能編寫了一小段代碼。使用Clojure在運行時動態綁定函數

(defn ^:dynamic state [x] 
    (odd x)) 

(defn even [x] 
    (if (= x 0) 
    (println "even") 
    (binding [state odd] (parity x)))) 

(defn odd [x] 
    (if (= x 0) 
    (println "odd") 
    (binding [state even](parity x)))) 

(defn parity [x] 
    (state (dec x))) 

它工作了罰款,但因爲我是完全地新的Clojure,我不知道這是否是
a)清潔功能的代碼(因爲奇數和偶數似乎有副作用?)
B)在運行時改變功能的方式應該是完成的

我會很感激任何形式的建議! :) -Zakum

回答

4

使用動態綁定的大多是品味的問題,但也有一些注意事項:

動態綁定是非常的明確傳遞調用堆棧上值的快捷方式。只有少數情況下,這是一個非常明顯的勝利;主要是像通過「不支持它們的API」傳遞「全局」配置設置/參數「。

依賴於動態綁定的API很難包裝成更明確的東西,而其他方式則更容易(通常可以半自動地完成)。

動態綁定對惰性序列或其他任何在當前調用堆棧之外進行評估的其他任何東西(如其他線程)都不會很好。總而言之,我認爲「更乾淨」的功能解決方案是將state作爲參數傳遞給parity,但是可以採取任何方式。

+0

感謝您的見解,Joost!所以我理解你是對的,我做的不是褻瀆嗎? 我知道這個事實,可以用不同的方式編寫這個功能。但是,我是否至少在Clojure中捕獲了動態綁定的想法? – Zakum

+0

個人而言,我會嘗試在使用動態綁定之前使用顯式值傳遞,這主要是因爲我提到的綁定的缺點,但它可以使代碼更加清晰和容易。 –

2

雖然能夠動態地將一個符號綁定到不同的函數上,但我猜你正在重新定義一個函數。

認爲它是這樣的:你的代碼創建一個符號,兩個函數,你動態綁定的符號,以不同的功能:

        +---> func1 
           /
symbol ---- [dynamic binding] ---< 
            \ 
            +---> func2 

動態綁定的作用僅限於的範圍binding調用。

我們要實現的是什麼,給定一個符號和功能,提供了功能的新的實現讓所有人都認爲是指它的代碼將訪問新的實現:

(defn func1 [...]) 

(var func1) ; ---> func1 

(defn func1 [...]) 

(var func1) ; ---> func1* 

和這樣的更改將永久影響所有使用func1的代碼。當你開發一個clojure時,這是一個正常的任務:你很可能會在正在運行的應用程序中打開一個REPL,並且你會多次重複定義相同的符號defdefn,重新定義所有的運動部件您的應用程序在飛行中。

如果您使用的是Emacs和SLIME/Swank,只要您在修改的Clojure源文件上點擊C-c C-k,就可能重新定義名稱空間中的所有函數,而無需重新啓動應用程序。

+0

我真的不認爲這是我的(我不知道,但^^)。 你告訴我的是我可以寫一個函數,使用它,重新定義它,再次使用它,等等,對吧?對我來說,這是靜態的,因爲更改是由程序員手動完成的。 我有興趣編寫在運行時**改變其他功能**的函數。更實際的例子是將日誌記錄添加到現有功能。 一個改變自己的函數將是一個更奇特的例子。 – Zakum

+0

Clojure中的AFAIK動態變量在Var綁定上運行,而不是在符號上運行。 – siefca