マクロ呼び出しは、マクロ名で始まるリストであるという点で、関数呼び出しと全く同じです。リストの残りの要素は、マクロの引数となります。
マクロ呼び出しの評価は、関数呼び出しの評価と同様に始まりますが、一点だけ決定的な違いがあります。それは、マクロの引数が、マクロ呼び出し内に現れる実際の式であるということです。これらの式は、マクロ定義に渡される前に評価されることはありません。対照的に、関数の引数は、関数呼び出しリストの各要素を評価した結果となります。
引数を受け取ると、Lispは関数を呼び出すのと同様にマクロ定義を呼び出します。マクロの引数変数には、マクロ呼び出し時の引数値がバインドされ、&rest
引数の場合はそのリストがバインドされます。そして、マクロ本体は関数本体と同様に実行され、その値を返します。
マクロと関数の2つ目の重要な違いは、マクロ本体から返される値が別のLisp式、すなわちマクロの展開と呼ばれる点にある。Lispインタプリタは、マクロから戻るとすぐにその展開の評価を行う。
展開は通常の手順で評価されるため、他のマクロへの呼び出しが含まれる場合があります。場合によっては同じマクロへの呼び出しになることもありますが、これは稀です。
なお、EmacsはコンパイルされていないLispファイルを読み込む際に、マクロを展開しようとします。これが常に可能とは限りませんが、可能な場合はその後の実行速度が向上します。プログラムの読み込み方法を参照してください。
macroexpandを呼び出すことで、特定のマクロ呼び出しの展開内容を確認できます。
この関数は、form
がマクロ呼び出しである場合にそれを展開します。その結果が別のマクロ呼び出しである場合は、マクロ呼び出しではないものが得られるまで、順次展開されます。それが
macroexpand によって返される値となります。form がそもそもマクロ呼び出しでない場合は、そのまま返されます。
なお、macroexpand は form
の部分式を参照しません(一部のマクロ定義では参照する場合もあります)。たとえそれら自体がマクロ呼び出しであっても、macroexpand はそれらを展開しません。
関数 macroexpand
は、インライン関数の呼び出しを展開しません。通常、インライン関数の呼び出しは通常の関数の呼び出しと比べて理解しにくいわけではないため、そのような処理は不要です。
environment が指定されている場合、現在定義されているマクロをシャドウするマクロ定義のアリリストを指定します。バイトコンパイルではこの機能を利用します。
(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 not expanded here.
macroexpand-all は macroexpand のようなマクロを展開しますが、トップレベルだけでなく、form 内のすべてのマクロを探して展開します。マクロが一つも展開されない場合、戻り値は eq から form となります。
上記の macroexpand で用いた例を macroexpand-all でも繰り返すと、macroexpand-all が埋め込まれた呼び出しを inc へと実際に展開することがわかります。
(macroexpand-all '(inc2 r s))
⇒ (progn (setq r (1+ r)) (setq s (1+ s)))
この関数は macroexpand
のようなマクロを展開しますが、展開は1ステップのみ行われます。結果が別のマクロ呼び出しである場合、macroexpand-1 はそれを展開しません。