2011-05-13 149 views
2

我工作的一个宏,我试图找出如何避免某些形式的扩张,采取以下和宏观例如,Clojure的宏扩展

 

(defmacro and 
    ([] true) 
    ([x] x) 
    ([x & next] 
    `(let [and# ~x] 
     (if and# (and [email protected]) and#)))) 
 

展开时,

(mexpand-all '(and 1 2 3)) 

变,

 

(let* [and__973__auto__ 1] 
     (if and__973__auto__ 
     (let* [and__973__auto__ 2] 
       (if and__973__auto__ 3 and__973__auto__)) 
     and__973__auto__)) 
 

在这种情况下,我需要做的是停止从扩大到让*让。

回答

3

递归宏观经济扩建工程通过重复扩张的形式,直到没有宏观扩张。这意味着如果你想递归地扩展一个宏,但是忽略某些形式,你必须编写自己的定制扩展器,或者找到别人的。

这里有一个简单的例子:

(defn my-expander [form] 
    (cond (not (list? form)) (mexpand-1 form) 
     (= (first form) 'let) form 
      :else (map my-expander (mexpand-1 form)))) 

请原谅我,如果我犯任何错误。 Scheme和CL比Clojure更强大。

- 编辑 - 请注意,上述函数不会扩展let语句的子表单。

5

咦?目前尚不清楚“停止”let的意思。 let是一个在clojure.core中定义的宏,编译器一无所知:它只能理解let*。如果你的宏扩展为let(以某种方式)拒绝进一步扩展,它将无法编译。

如果你想单独检查你的宏的输出,而不必担心递归扩展它,你应该使用macroexpandmacroexpand-1而不是mexpand-all的东西。我不知道mexpand-all来自哪里,但是当我需要类似的东西时,我使用clojure.walk/macroexpand-all

+0

我想要做的是递归地扩展除let形式之外的所有东西。顺便说一句,mexpand来自contrib macro-utils – 2011-05-13 02:26:05

1

使用macroexpand-1执行单个级别的宏扩展。

加载你and宏,这个表达式后:

user=> (macroexpand-1 '(and 1 2 3)) 

产量:

(clojure.core/let [and__1__auto__ 1] (if and__1__auto__ (clojure.core/and 2 3) and__1__auto__))