Macros 在未定义符号上迭代的宏

Macros 在未定义符号上迭代的宏,macros,clojure,metaprogramming,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 ::Bas

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

(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时,它仍然有效。有办法解决这个问题吗?如果可能的话,没有评估会更好

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

(empties Base Person Animal)
;equivalent to:
;(ty Base)
;(ty Person)
;(ty Animal)
这是错误的。您的
清空
调用意味着
清空
的宏扩展函数将符号
Base
Person
Animal
作为参数获取。然后对每个调用的
ty
宏进行求值,但不返回任何内容,因为
doseq
始终返回nil。因此,
清空
调用的扩展代码为nil。您需要从宏函数返回一个表单。您应该将多个表单包装成一个
do
,并实际将所有子表单返回到该表单:

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

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

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

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

有趣。请注意,您的解决方案似乎对我不起作用:我得到了IllegalArgumentException:不知道如何从“do”行
(fn[arg])
,而不是
(fn(arg))
上的clojure.lang.Symbol创建ISeq。但他总的来说是对的:
doseq
在宏中通常是错误的,当然,如果目标是这样的话,可以扩展成
doseq
。@daniel ribeiro为我工作
user=>(清空)| user.Empty | user=>(prn Empty)| user.Empty
。谢谢@kotarak。我在REPL上使用过,效果很好。Intellij的LaClojure搞砸了一些东西,但它不起作用。奇怪的我很抱歉之前没有尝试REPL。注意:这个答案是正确的,比Svante的更简单。然而,他的回答解释了为什么这个答案是正确的。我希望能够选择两者。