Next: Repeated Expansion, Previous: Surprising Local Vars, Up: Problems with Macros [Contents][Index]
マクロ定義自体がeval
(Evalを参照)の呼び出しなどによりマクロ引数式を評価した場合には別の問題が発生します。まだ呼び出し側のコンテキスト(マクロ展開が評価される場所)にアクセスできない場合には、コード実行の遥か前にマクロが展開されることを考慮する必要があります。
更にマクロ定義でlexical-binding
バインディングを使用していなければ、ユーザーの同じ名前の変数ををマクロの正規引数が隠してしまうかもしれません。マクロの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
と競合しているからです。
更に上記の(foo x)
の展開は、コードがコンパイル済みの際には(setq x
'b)
の実行は後刻そのコードが実行されるときだけ発生するのに、(foo
x)
はコンパイル時に展開されるので、異なる結果をリターンしたりエラーをシグナルするでしょう。
この問題を避けるためには、マクロ展開形の計算では引数式を評価しないでください。かわりにその式をマクロ展開形の中に置き換えれば、その値は展開形の実行の一部として計算されます。これは、このチャプターの他の例が機能する方法です。