2011-08-07 34 views
3

当一个应用宏多次另一个宏,裸符号不被插入到当前上下文中:宏遍历未定义的符号

(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) 

最后一行给出:“无法解析符号:空在这上下文“,即使在使用直接宏观时,它也可以工作。任何方式来解决这个问题?如果可能的话没有评估它会好得多。

回答

2

FWIW,我喜欢写@斯万的解决方案

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

这也是相当接近你的doseq方法的结构。

+0

@ daniel-ribeiro适合我。 'user =>(清空)| user.Empty | user =>(prn Empty)| user.Empty'。 – kotarak

+0

谢谢@kotarak。我在REPL上使用过它,并且它工作正常。 Intellij的LaClojure搞砸了一些东西,它不起作用。奇怪的。我很抱歉没有尝试过REPL。 –

+0

注意:这个答案比Svante的正确和简单。然而,他的回答解释了为什么这一个是正确的。希望能够选择两者。 –

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

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

这是错误的。您的empties调用意味着empties的宏扩展函数的符号为Base,PersonAnimal。然后它评估每个宏的调用ty,但不返回任何内容,因为doseq总是返回nil。所以,来自empties调用的扩展代码是零。你需要从你的宏函数中返回一个表单。你应该换多种形式成do,实际上返回所有的子表单到:

(defmacro empties [& args] 
    `(do [email protected](map (fn [arg] 
       `(ty ~arg)) 
       args))) 
+0

有趣。请注意,您的解决方案似乎并不适用于我,虽然:我得到IllegalArgumentException:不知道如何创建ISeq:“do”行 –

+0

(fn [arg])'上的clojure.lang.Symbol,而不是'(fn(arg))'。但是他总体上是正确的:'doseq'在宏中通常是错误的,但如果这是目标,那么将*扩展到* doseq'当然是好的。 – amalloy

+0

Oups,对不起!纠正。 – Svante