2009-07-06 121 views
7

我試圖創建一個函數來創建一個新的基地與另一個結構作爲基地,並作爲一個開始,我試圖做一個宏,將創建一個新的結構與舊的相同的領域。我認爲應該做到這一點的宏我有低於,但它給了以下錯誤:Clojure宏問題

java.lang.Exception: Can't use qualified name as parameter: user/p1__132 

宏:

(defstruct bintree :data :left :right) 
(def a (struct bintree 3)) 
(prototype bintree a) 

(defmacro prototype [structure obj] 
    `(apply struct ~structure (map #(~obj %) (keys ~obj)))) 

使用示例在這種情況下期望的輸出將是

{:data 3 :left nil :right nil} 
+0

我是clojure的新手,但是我發現這個鏈接:http://osdir.com/ml/java.clojure.user/2008-03/msg00108.html – seth 2009-07-06 23:16:03

回答

8

鏈接seth張貼爲您的問題的評論包含答案(罪魁禍首是處理匿名函數的參數的方式);下面,使用gensym的說法,應該工作:

(defmacro prototype [structure obj] 
    `(apply struct ~structure (map (fn [x#] (~obj x#)) (keys ~obj)))) 
3

這裏有一個固定的版本:

(defmacro prototype [structure obj] 
    `(apply struct ~structure (map ~obj (keys ~obj)))) 

爲什麼這需要做個宏?功能也可以使用:

(defn prototype [structure obj] 
    (apply struct structure (map obj (keys obj)))) 

爲什麼要複製結構?結構是不可變的,所以複製它們是沒有用的。這個函數做同樣的事情,如上圖所示:

(defn prototype [structure obj] obj) 

如果你想創建一個新的結構,附加鍵&值,使用assoc

2

你不應該使用#()宏裏面。

user> (macroexpand-1 `(foo #(bar %) baz)) 
(user/foo (fn* [user/p1__2047] (user/bar user/p1__2047)) user/baz)

這並不是說fn*形式在其參數列表中的名稱空間限定的符號。這是你得到的錯誤。您應該在宏中避免使用這種特殊的閱讀器語法,而應使用長格式。