3

在 Programming 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#))))

为什么chain宏一直扩展不是and?为什么它不扩展为以下内容:

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

2 回答 2

2

macroexpand一遍又一遍地扩展最外层的形式,直到它得到一个非宏观的结果。如果您只想查看单个宏扩展阶段的输出,请使用macroexpand-1.

所以区别在于,chain's 递归调用是第一个,而and's 不是。

于 2012-07-04T03:14:05.940 回答
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(由于 amalloy 给出的原因)相同:

user=> (macroexpand-all '(chain a b c))
(. (. a b) c)
于 2012-07-05T04:32:13.120 回答