3

プログラミング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)
4

2 に答える 2

2

macroexpand非マクロ結果が得られるまで、最も外側のフォームを何度も展開します。マクロ拡張の単一フェーズの出力のみを表示する場合は、を使用しますmacroexpand-1

したがって、違いは、chain'sの再帰呼び出しが最初であり、and'sはそうではないということです。

于 2012-07-04T03:14:05.940 に答える
2

私にとって、アマロイの回答はあなたの質問に直接答えます。ただし、質問の下に隠されている場合は、完全にマクロ拡張された形式の何かを表示する方法を疑問に思っている場合は、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)
于 2012-07-05T04:32:13.120 に答える