Next: Repeated Expansion, Previous: Surprising Local Vars, Up: Problems with Macros [Contents][Index]
マクロ定義自体が、eval
(Evalを参照してください)の呼び出しなどによりマクロ引数式を評価した場合には、別の問題が発生します。その引数がユーザーの変数を参照する場合、ユーザーがマクロ引数と同じな前で変数をしようとした場合に問題となるでしょう。マクロのbodyないでは、マクロ引数のバインディングは、その変数のもっともローカルなバインディングなので、そのフォーム内部の任意の参照は、それを参照するように評価されます。以下は例です:
(defmacro foo (a) (list 'setq (eval a) t))
(setq x 'b) (foo x) → (setq b t) ⇒ t ;b
がセットされる。 ;; but (setq a 'c) (foo a) → (setq a t) ⇒ t ; しかし、これはc
ではなくa
がセットされる。
ユーザーの変数の名前がa
かx
かということで、違いが生じています。これはa
が、マクロの引数変数a
と競合しているからです。
マクロ定義内でのeval
の呼び出しにまつわる別の問題は、それがおそらくコンパイル時にあなたが意図したことを行わないだろうということです。バイトコンパイラーは、そのプログラム自身の(あなたがeval
でアクセスしたいと望む)計算は発生せず、ローカル変数バインディングも存在しないプログラムのコンパイル時にマクロ定義を実行します。
この問題を避けるためには、マクロ展開形の計算では引数式を評価しないでください。かわりにその式をマクロ展開形の中に置き換えれば、その値は展開形の実行の一部として計算されます。これは、このチャプターの他の例が機能する方法です。