2012-07-04 113 views
3

在「Programming Clojure(Stuart)」一書中,當閱讀宏如何擴展時,我感到困惑。如何在clojure中擴展宏?

user=> (defmacro chain 
      ([x form] (list '. x form)) 
      ([x form & more] (concat (list 'chain (list '. x form)) more))) 
#'user/chain 

上述宏可以展開爲:

user=> (macroexpand '(chain a b c)) 
(. (. a b) c) 

但下面只膨脹到第一電平:

user=> (macroexpand '(and a b c)) 
(let* [and__3822__auto__ a] 
    (if and__3822__auto__ (clojure.core/and b c) and__3822__auto__)) 

宏源:

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

爲什麼宏觀擴張一路,但不是?爲什麼不擴大到類似以下內容:

user=> (macroexpand '(chain a b c d)) 
(. (chain a b c) d) 

回答

2

macroexpand遍地擴展最形式,直到它得到一個非宏結果。如果您只想看到單個宏觀展開階段的輸出,請使用macroexpand-1

所以區別在於,chain的遞歸調用是第一個,而and的不是。

2

對我來說,amalloy的回覆直接回答你的問題。然而,如果你隱藏在你的問題之下,你想知道如何展示完全宏觀展開的東西,我會指着你的方向clojure.walkmacroexpand-all。使用同樣的例子,現在使用宏展開式全部:

user=> (macroexpand-all '(and a b c)) 
(let* [and__3546__auto__ a] 
    (if and__3546__auto__ 
    (let* [and__3546__auto__ b] 
     (if and__3546__auto__ c and__3546__auto__)) 
    and__3546__auto__)) 

所有的宏都被擴展了。另請注意,對於您的第一個示例,其行爲將與macroexpand(由於amalloy給出的原因)相同:

user=> (macroexpand-all '(chain a b c)) 
(. (. a b) c)