宏迭代未定义的符号

时间:2011-08-07 08:24:44

标签: macros clojure metaprogramming

当使用另一个宏多次应用宏时,裸符号不会插入到当前上下文中:

(defmacro ty [type]
  `(deftype ~type []))

(defmacro empties [& args]
  (doseq [arg args]
    `(ty ~arg))
  )

(empties Base Person Animal)
;equivalent to:
;(ty Base)
;(ty Person)
;(ty Animal)


(derive ::Person ::Base)
(derive ::Animal ::Base)
(ty Me)
(prn ::Me)
(prn Me)
(empties Empty)
(prn ::Empty)
(prn Empty)

最后一行给出:“无法解析符号:在此上下文中为空”,即使使用直接宏ty,它也可以。有办法解决这个问题吗?如果没有eval可能会更好。

2 个答案:

答案 0 :(得分:5)

(defmacro empties [& args]
  (doseq [arg args]
    `(ty ~arg)))

(empties Base Person Animal)
;equivalent to:
;(ty Base)
;(ty Person)
;(ty Animal)

这是错误的。您的empties来电意味着empties的宏扩展功能会将符号BasePersonAnimal作为参数。然后它会为每个调用ty宏调用,但不返回任何内容,因为doseq总是返回nil。因此,empties调用的扩展代码为零。您需要从宏函数返回单个表单。您应该将多个表单包装到do中,并实际将所有子表单返回到:

(defmacro empties [& args]
  `(do ~@(map (fn [arg]
               `(ty ~arg))
              args)))

答案 1 :(得分:2)

FWIW,我更喜欢将@ Svante的解决方案写成

(defmacro empties [& args]
  (cons `do
        (for [arg args]
          `(ty ~arg))))

这也非常接近doseq方法的结构。