2010-05-15 55 views
19

我試圖(作爲一種自學習練習)創建一個Clojure宏,該宏將生成將函數應用於整數序列並對結果進行求和的代碼。控制Clojure宏中的符號生成

F(0)+ F(1)+ F(2)+ F(3)

這是我的嘗試:

(defmacro testsum [func n] 
    `(fn [x#] (+ [email protected](map (fn [i] `(~func x#)) (range n))))) 

然而事情似乎出差錯X#gensym和我結束了兩個不同版本的x,因此功能不起作用:

(macroexpand '(testsum inc 3)) 

給出:

(fn* ([x__809__auto__] 
    (clojure.core/+ 
    (inc x__808__auto__) 
    (inc x__808__auto__) 
    (inc x__808__auto__)))) 

這幾乎正是我想除了不同的809和808版本的x ......

我在做什麼錯了?我認爲汽車gensym是爲了創造一個唯一的符號來完成這種目的?有沒有更好的方法來做到這一點?

回答

24

foo# -style gensyms只在創建它們時的語法引用內有效。在你的代碼,在不同的語法引號塊中創建兩個x# S:

(defmacro testsum [func n] 
    `(fn [x#] (+ [email protected](map (fn [i] `(~func x#)) (range n))))) 
    ^- s-q1  ^-unquote  ^- s-q2 

爲了解決這個問題,使用一個明確的(gensym)電話:

(defmacro testsum [func n] 
    (let [x (gensym "x")] 
    `(fn [~x] (+ [email protected](map (fn [i] `(~func ~x)) (range n)))))) 

而宏擴展((macroexpand '(testsum inc 3))):

(fn* ([x4966] (clojure.core/+ (inc x4966) (inc x4966) (inc x4966)))) 
+3

作爲一種事後的考慮,也可以用''''''''''替換'(gensym「x」)',儘管我從來沒有見過任何人爲了在主要的擴張形式。 – 2010-05-15 13:02:06

+0

真棒米迦勒 - 非常感謝! 來自Java世界後,仍然圍繞在符號周圍...... – mikera 2010-05-15 13:03:33