Next: , Previous: , Up: Macros   [Contents][Index]


14.2 マクロ呼び出しの展開

マクロ呼び出しは関数の呼び出しと同じ外観をもち、マクロの名前で始まるリストで表されます。そのリストの残りの要素はマクロの引数になります。

マクロ呼び出しの評価は1つの重大な違いを除いて、関数の評価と同じように開始されます。重要な違いとはそのマクロの引数はマクロ呼び出し内で実際の式として現れます。これらの引数はマクロ定義に与えられる前には評価されません。対象的に関数の引数はその関数の呼び出しリストの要素を評価した結果です。

こうして得た引数を使用して、Lispは関数呼び出しのようにマクロ定義を呼び出します。マクロの引数変数はマクロ呼び出しの引数値にバインドされるか、a &rest引数の場合は引数地のリストになります。そしてそのマクロのbodyが実行されて、関数bodyが行うようにマクロbodyの値をリターンします。

マクロと関数の2つ目の重要な違いは、マクロのbodyからリターンされる値が代替となるLisp式であることで、これはマクロの展開(expansion)としても知られています。Lispインタープリターはマクロから展開形が戻されると、すぐにその展開形の評価を行います。

展開形は通常の方法で評価されるので、もしかしたらその展開形は他のマクロの呼び出しを含むかもしれません。一般的ではありませんが、もしかすると同じマクロを呼び出すかもしれません。

EmacsはコンパイルされていないLispファイルをロードするときに、マクロの展開を試みることに注意してください。これは常に利用可能ではありませんが、もし可能ならそれ以降の実行の速度を改善します。How Programs Do Loadingを参照してください。

macroexpandを呼び出すことにより、与えられたマクロ呼び出しにたいする展開形を確認することができます。

Function: macroexpand form &optional environment

この関数はそれがマクロ呼び出しならformを展開する。結果が他のマクロ呼び出しなら、結果がマクロ呼び出しでなくなるまで順番に展開を行う。これがmacroexpandからリターンされる値になる。formがマクロ呼び出しで開始されなければ、与えられたformをそのままリターンする。

macroexpandは、(たとえいくつかのマクロ定義がそれを行っているとしても)formの部分式(subexpression)を調べないことに注意。たとえ部分式自身がマクロ呼び出しでも、macroexpandはそれらを展開しない。

関数macroexpandはインライン関数の呼び出しを展開しない。なぜならインライン関数の呼び出しは、通常の関数呼び出しと比較して理解が難しい訳ではないので、通常はそれを行う必要がないからである。

environmentが与えられたら、それはそのとき定義されているマクロをシャドーするマクロのalistを指定する。バイトコンパイルではこの機能を使用している。

(defmacro inc (var)
    (list 'setq var (list '1+ var)))

(macroexpand '(inc r))
     ⇒ (setq r (1+ r))

(defmacro inc2 (var1 var2)
    (list 'progn (list 'inc var1) (list 'inc var2)))

(macroexpand '(inc2 r s))
     ⇒ (progn (inc r) (inc s))  ; ここではincは展開されない
Function: macroexpand-all form &optional environment

macroexpand-allmacroexpandと同様にマクロを展開するが、ドップレベルだけではなくform内のすべてのマクロを探して展開する。展開されたマクロがなければリターン値はformeqになる。

上記macroexpandで使用した例をmacroexpand-allに用いると、macroexpand-allincに埋め込まれた呼び出しの展開を行うことを確認できる

(macroexpand-all '(inc2 r s))
     ⇒ (progn (setq r (1+ r)) (setq s (1+ s)))
Function: macroexpand-1 form &optional environment

この関数はmacroexpandのようにマクロを展開するが、展開の1ステップだけを行う。結果が別のマクロ呼び出しならmacroexpand-1はそれを展開しない。