在编写Clojure(Stuart)一书中,当读到宏如何扩展时,我感到困惑。
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 ~@next) and#))))
为什么 链 宏一直在扩展,但 和 不是?为什么不扩展到以下内容:
user=> (macroexpand '(chain a b c d))
(. (chain a b c) d)
答案 0 :(得分:2)
macroexpand
反复展开最外面的表单,直到获得非宏结果。如果您只想查看单个宏展开阶段的输出,请使用macroexpand-1
。
所以区别在于,chain
的递归调用是第一个,而and
则不是。
答案 1 :(得分:2)
对我来说,amalloy的回复直接回答了你的问题。但是,如果隐藏在你的问题之下,你想知道如何展示完全宏观扩展的形式,我会指向clojure.walk的macroexpand-all
方向。使用相同的示例,现在使用macroexpand-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
相同(由于合金的原因):
user=> (macroexpand-all '(chain a b c))
(. (. a b) c)