Next: , Previous: , Up: Problems with Macros   [Contents][Index]


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

マクロ定義自体が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がセットされる

ユーザーの変数の名前がaxかということで違いが生じています。これはaがマクロの引数変数aと競合しているからです。

マクロ定義内でのevalの呼び出しにまつわる別の問題は、それがおそらくコンパイル時にあなたが意図したことを行わないだろうということです。バイトコンパイラーは、そのプログラム自身の(あなたがevalでアクセスしたいと望む)計算が発生しない、ローカル変数バインディングも存在しないプログラムのコンパイル時にマクロ定義を実行します。

この問題を避けるためには、マクロ展開形の計算では引数式を評価しないでください。かわりにその式をマクロ展開形の中に置き換えれば、その値は展開形の実行の一部として計算されます。これは、このチャプターの他の例が機能する方法です。