Next: , Previous: Surprising Local Vars, Up: Problems with Macros


12.6.3 展開形におけるマクロ引数の評価

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を設定する

ユーザーの引数の名前がaxかで違いがでます。 というのは、マクロ引数の変数aaが衝突するからです。

マクロ定義内でevalを呼び出したときの別の問題点は、 コンパイルしたプログラムでは、意図した動作をしないだろうということです。 バイトコンパイラは、プログラムをコンパイル中にマクロ定義を実行しますから、 (evalで参照したい)プログラムそのものの計算は行われず、 そのローカル変数の束縛も存在しません。

これらの問題を回避するには、 マクロ展開の計算過程では、引数の式を評価しないことです。 そのかわりに、マクロ展開では式の置換を使って、 展開時にその値が計算されるようにします。 このようにすれば、本章の他の例題は動作します。