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的更简单。然而,他的回答解释了为什么这个答案是正确的。我希望能够选择两者。