私の知識不足を例を挙げて説明したいと思います。
次の2つのマクロ定義を使用して、
(defmacro for (var from init to final do &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
(let ((tempvar 'max))
`(let ((,var ,init)
(,tempvar ,final))
(while (<= ,var ,tempvar)
,@body
(setq ,var (1+ ,var))))))
(defmacro for (var from init to final do &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
(let ((tempvar (make-symbol "max")))
`(let ((,var ,init)
(,tempvar ,final))
(while (<= ,var ,tempvar)
,@body
(setq ,var (1+ ,var))))))
最初のマクロmax
は、本体で発生する可能性がある名前付きの変数をシャドウし、2番目のマクロはシャドウしません。これは、次の例で示すことができます。
(let ((max 0)) ;; this variable is shadowed if the first macro defintion is used
(for i from 1 to 3 do
(setq square (* i i))
(if (> square max)
(princ (format "\n%d %d" i square)))))
私が学んだ限り、マクロ呼び出しの評価は次のように機能します。
マクロは2回評価されます。最初に本体が評価され、フォームを返します。その後、このフォームは再度評価されます。
ここまでは順調ですね。
しかし、マクロが実際にlispフォームであるテキストのチャンクを返し、それが解釈されると仮定すると、上記の例を理解できなくなる競合が発生します。
make-symbol
シャドウイングが発生しないように、使用する2番目のマクロが返すテキストのチャンクは何ですか?私の理解では、非常にありそうにないランダムに選択されたシンボル名が理にかなっています。
pp-macroexpand...
両方のマクロを使用すると、同じ展開が返されます。
この混乱から誰かが私を助けることができますか?
1
これはテキストのチャンクではなく、シンボルのリストです。一部は特別であり、したがって他の人と衝突することはありません...
—
wasamasa
あなたが設定した場合
—
npostavs
print-gensym
とprint-circle
にt
、あなたはマクロ展開の違いを見ることができます。
@wasamasaそれらがどのように特別であり、これが実際に機能するかはまさに私が理解したいものです。
—
クレメラ
@npostavsおかげで、返されたフォームは異なり、これはデフォルト設定では表示されません。...非抑留シンボルはに置き換えられ
—
クレメラ
#:max
ます。どういう意味ですか ?もっと詳しく知りたいです。