我正在尝试使用另一个结构作为基础创建一个创建新基础的函数,作为一个开始,我尝试创建一个宏,该宏将创建一个与旧结构相同的新结构。我认为应该这样做的宏在下面,但它给出了以下错误:
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}
答案 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*
表单在其参数列表中具有名称空间限定符号。这就是你得到的错误。您应该在宏中避免使用这种特殊的读者语法,而是使用长格式。