2013-07-10 47 views
4

我有一個像這樣定義的函數規範,我想將它計算到一個函數對象中,以便我可以傳遞。如何在clojure中將列表形式轉換爲函數

(def spec '(foo [n] (* 2 n))) 

我可以創建這樣

(defmacro evspec [name arg & body] `(defn ~name [~arg] [email protected])) 

那麼下面的電話給我函數foo的宏。當3調用(FOO 3),將返回6.

(evspec foo n (* 2 n)) 

但是,如果我從我的規格函數體上面定義,函數foo退換不會評估體形式(* 2 N)相反,它返回身體形式。

(let [foo (first spec) arg (first (second spec)) body (last spec)] 
    (evspec foo arg body)) 

user=> (foo 3) 
(* 2 n) 

我注意到現在創建foo的功能是$ EVAL $ foo的

user=> foo 
#<user$eval766$foo__767 [email protected]> 

而工作FOO功能

user=> foo 
#<user$foo [email protected]> 

有誰能夠解釋爲什麼差別,我怎麼能讓它起作用 ?我想有一種方式沒有在eval上回復?來自javascript的背景,總覺得eval是邪惡的。

+0

如果你想傳遞一個函數對象,只需使用(defn foo [...)並傳遞符號foo。 –

回答

4

根本無法做到這一點,一般沒有eval。宏只是一個函數,它在編譯時直接傳遞它的參數表達式(當它在運行時通常根本不可能知道它們的值是什麼時)。特別是,在問號文本中的let表格內呼叫evspec,其中返回值爲(* 2 n)evspec宏擴展器字面上看到符號foo和符號n作爲其位置參數和(body)(包含單個符號的seq作爲其「休息」論點;返回值與這些輸入一致。

但是,使用eval這種目的是非常好的。記住它有相當大的運行時間成本是很重要的,所以你會希望稍微謹慎地使用它,但是一旦你使用eval產生一個函數,它就是一個非常好的Clojure函數,和其他函數一樣快。

此外,注意,雖然在JavaScript eval上的文字工作,Clojure的eval運行在Clojure的數據結構 - 實際上相同數據結構的宏操作上 - 這無疑使得它不太容易出錯。

+0

+1對數據結構進行clojure評估,而js對文本進行評估! – haijin

相關問題