Clojure宏观问题

时间:2009-07-06 23:04:49

标签: clojure

我正在尝试使用另一个结构作为基础创建一个创建新基础的函数,作为一个开始,我尝试创建一个宏,该宏将创建一个与旧结构相同的新结构。我认为应该这样做的宏在下面,但它给出了以下错误:

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

宏:

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

使用示例:

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

在这种情况下,所需的输出是

{:data 3 :left nil :right nil}

3 个答案:

答案 0 :(得分:8)

作为对您的问题的评论发布的链接seth包含答案(罪魁祸首是处理匿名函数的参数的方式);使用gensym参数的以下内容应该有效:

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

答案 1 :(得分: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 :(得分:2)

您不应在宏中使用#()

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

并非fn*表单在其参数列表中具有名称空间限定符号。这就是你得到的错误。您应该在宏中避免使用这种特殊的读者语法,而是使用长格式。