2011-05-13 193 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__))