Next: Repeated Expansion, Previous: Surprising Local Vars, Up: Problems with Macros
eval
(see Eval)を呼び出すなどして、
マクロ定義そのものの中でマクロ引数の式を評価すると、
別の問題を生じます。
引数でユーザーの変数を参照する場合、
ユーザーがマクロ引数の1つと同じ名前を使っていると、
問題になります。
マクロ本体の内側では、マクロ引数の束縛が最ローカルな束縛ですから、
そのフォームの内側からの参照は、この束縛を使います。
例を示しましょう。
(defmacro foo (a) (list 'setq (eval a) t)) foo (setq x 'b) (foo x) ==> (setq b t) t ;b
を設定する ;; しかし (setq a 'c) (foo a) ==> (setq a t) t ;c
ではなくa
を設定する
ユーザーの引数の名前がa
かx
かで違いがでます。
というのは、マクロ引数の変数a
とa
が衝突するからです。
マクロ定義内でeval
を呼び出したときの別の問題点は、
コンパイルしたプログラムでは、意図した動作をしないだろうということです。
バイトコンパイラは、プログラムをコンパイル中にマクロ定義を実行しますから、
(eval
で参照したい)プログラムそのものの計算は行われず、
そのローカル変数の束縛も存在しません。
これらの問題を回避するには、 マクロ展開の計算過程では、引数の式を評価しないことです。 そのかわりに、マクロ展開では式の置換を使って、 展開時にその値が計算されるようにします。 このようにすれば、本章の他の例題は動作します。