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
でアクセスしたいと望む)計算が発生しない、ローカル変数バインディングも存在しないプログラムのコンパイル時にマクロ定義を実行します。
この問題を避けるためには、マクロ展開形の計算では引数式を評価しないでください。かわりにその式をマクロ展開形の中に置き換えれば、その値は展開形の実行の一部として計算されます。これは、このチャプターの他の例が機能する方法です。