7

我正在尝试创建一个函数来创建一个以另一个结构为基础的新基础,作为开始,我尝试制作一个宏来创建一个与旧结构具有相同字段的新结构。我认为应该执行此操作的宏如下,但它给出了以下错误:

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}
4

3 回答 3

8

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

(defmacro prototype [structure obj]
  `(apply struct ~structure (map (fn [x#] (~obj x#)) (keys ~obj))))
于 2009-07-06T23:29:41.580 回答
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.

于 2009-07-06T23:27:11.930 回答
2

您不应该#()在宏中使用。

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

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

于 2009-07-06T23:31:44.307 回答