% Variable *MACROEXPAND-HOOK*
Variable *MACROEXPAND-HOOK*
3つの引数(マクロ関数、マクロフォーム、環境オブジェクト)を 受け付ける関数指定子。
関数funcall
と同等の関数指定子。
しかし追加で実装依存の副作用を持つかもしれません。
macroexpand-1
は
この値を展開インターフェイスとしてフックし
マクロ展開処理を制御するために使用します。
マクロフォームを展開するときに、
その関数を3つの引数(マクロ関数、マクロフォーム、環境オブジェクト)で呼び出し、
マクロフォームを展開します。
環境オブジェクトは動的生存期間を持っており、
その関数オブジェクトがマクロ展開関数の動的生存期間の外で
参照されたときの結果は未定義です。
(defun hook (expander form env)
(format t "Now expanding: ~S~%" form)
(funcall expander form env)) => HOOK
(defmacro machook (x y) `(/ (+ ,x ,y) 2)) => MACHOOK
(macroexpand '(machook 1 2)) => (/ (+ 1 2) 2), true
(let ((*macroexpand-hook* #'hook)) (macroexpand '(machook 1 2)))
>> Now expanding (MACHOOK 1 2)
=> (/ (+ 1 2) 2), true
なし。
macroexpand
,
macroexpand-1
,
funcall
,
3.1. 評価
初期値の動作は、ただマクロ関数を起動するだけであり、 引数はマクロフォームと環境オブジェクトの2つになります。
ユーザーとそのプログラムは、マクロ展開の仕組みを用いて、 変数の代入をカスタイマイズしたりトレースすることができます。 しかし、その変数がグローバルリソースであり、 複数のプログラムによって共有される可能性がある場合、 例えば2つのプログラムが変数の正しくないセッティングに依存していたときは それらのプログラムは同じLispイメージ上でも正しく実行されないかもしれません。 そのような理由で、デバッグ用途に限定して使用したほうがよいでしょう。
*macroexpand-hook*
を自分の関数に置き換えるユーザーは、
以前のフックの値を保存しておいて、
自分の関数上で以前の値を呼び出すように考える必要があります。