次: , 前: Simple Macro, 上: Macros


12.2 マクロ呼び出しの展開

マクロ呼び出しはマクロ名で始まるリストであり、 関数呼び出しとほとんど同じに見えます。 リストの残りの要素はマクロの引数です。

マクロ呼び出しの評価は、関数呼び出しの評価のように始められますが、 1つだけ重要な違いがあります。 マクロの引数は、マクロ呼び出しに現れた実際の引数です。 マクロ定義に渡すまえに、それらを評価しません。 一方、関数の引数は、関数呼び出しのリストの要素を評価した結果です。

引数を得ると、Lispは関数定義を起動するのと同様にマクロ定義を起動します。 マクロの引数変数は、マクロ呼び出しの引数値や &rest引数の場合にはそれらのリストに束縛されます。 そうして、マクロ本体を実行し、関数本体と同様に値を返します。

マクロと関数の重要な違いの2つめは、 マクロ本体が返した値はマクロ呼び出しの値ではないことです。 戻り値は値を計算するためのかわりの式であり、 これをマクロの展開形(expansion)といいます。 Lispインタープリタは、マクロから戻ってくると、 ただちに展開形を評価することへ進みます。

展開形は、通常どおりに評価されるので、 展開形から他のマクロを呼び出してもかまいません。 同一のマクロを呼び出してもかまいませんが、 それは一般的ではありません。

macroexpandを呼ぶと、指定したマクロの展開形を調べることができます。

— 機能: macroexpand form &optional environment

この関数は、formがマクロ呼び出しならば、それを展開する。 その結果がまた別のマクロ呼び出しであれば、さらに展開する。 マクロ呼び出しでない結果を得るまでこれを繰り返す。 それが、macroexpandが返す値である。 formが始めからマクロ呼び出しでなければ、 与えられたとおりのものを返す。

macroexpandformの部分式を調べないことに注意してほしい (ただし、マクロ定義によっては調べるかもしれない)。 部分式がマクロ呼び出しであったとしても、 macroexpandはそれらを展開しない。

関数macroexpandは、インライン関数の呼び出しは展開しない。 インライン関数の呼び出しを理解することは普通の関数呼び出しを理解するのと かわりないので、通常、そのような展開を行う必要はない。

environmentを指定すると、 それは、現在定義済みのマクロを隠すマクロ定義の連想リストを表す。 バイトコンパイルではこの機能を使う。

          (defmacro inc (var)
              (list 'setq var (list '1+ var)))
               => inc
          
          (macroexpand '(inc r))
               => (setq r (1+ r))
          
          (defmacro inc2 (var1 var2)
              (list 'progn (list 'inc var1) (list 'inc var2)))
               => inc2
          
          (macroexpand '(inc2 r s))
          
               => (progn (inc r) (inc s))  ; ここではincを展開しない