30

だから...私はスキームr6rsに不慣れで、マクロを学んでいます。誰かが「衛生」とはどういう意味かを私に説明できますか?

前もって感謝します。

4

6 に答える 6

26

衛生は、マクロのコンテキストでよく使用されます。衛生的なマクロは、展開中のコードに干渉するリスクのある変数名を使用しません。これが例です。orマクロを使用して特殊なフォームを定義するとします。直感的に、

(or a b c ... d)のようなものに拡張されます(let ((tmp a)) (if tmp a (or b c ... d)))(or)(簡単にするために、空のケースは省略しています。)

さて、tmp上記のスケッチ展開のように名前が実際にコードに追加された場合、同じ名前の別の変数に干渉する可能性があるため、衛生的ではなく、悪い結果になります。言う、私たちは評価したかった

(let ((tmp 1)) (or #f tmp))

直感的な拡張を使用すると、これは次のようになります

(let ((tmp 1)) (let ((tmp #f)) (if tmp (or tmp)))

tmpfromマクロは最も外側のをシャドウイングするためtmp、結果は#fの代わりになり1ます。

ここで、マクロが衛生的である場合(Schemeでは、を使用すると自動的に適用されますsyntax-rules)、展開に名前を使用する代わりにtmp、コード内の他の場所に表示されないことが保証されているシンボルを使用します。CommonLispで使用できますgensym

PaulGrahamのOnLispは、マクロに関する高度な資料を持っています。

于 2010-06-09T22:56:31.460 に答える
9

マクロが使用される場所に単純に展開されることを想像すると、マクロで変数を使用する場合、そのマクロが使用される場所にすでに変数が定義されている可能性があることも想像できaます。a

これはあなたが望むものではありませaん!

このようなことが起こらないマクロシステムは、衛生と呼ばれます。

この問題に対処するにはいくつかの方法があります。1つの方法は、マクロで非常に長く、非常に不可解で、非常に予測不可能な変数名を使用することです。

これのもう少し洗練されたバージョンは、gensym他のいくつかのマクロシステムで使用されるアプローチです。プログラマーが非常に長く、非常に不可解で、非常に予測不可能な変数名を思い付く代わりに非常にgensym長い、非常に長いを生成する関数を呼び出すことができます。不可解で、非常に予測不可能、一意の変数名。

そして、私が言ったように、衛生的なマクロシステムでは、そもそもそのような衝突は起こり得ません。マクロシステムを衛生的にする方法はそれ自体が興味深い質問であり、Schemeコミュニティはこの質問に数十年を費やしており、それを行うためのより良い方法を考え続けています。

于 2010-06-09T22:53:38.040 に答える
3

この言語がまだ使われていることを知ってとてもうれしいです!衛生的なコードは、(マクロを介して)挿入されたときに既存の変数との競合を引き起こさないコードです。

ウィキペディアにはこれに関する多くの良い情報があります:http://en.wikipedia.org/wiki/Hygienic_macro

于 2010-06-09T22:55:23.117 に答える
2

これが私が見つけたものです。それが何を意味するのかを説明することは、まったく別の問題です!

http://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-ZH-1.html#node_toc_node_sec_12.1

于 2010-06-09T22:53:49.227 に答える
2

マクロはコードを変換します。1ビットのコードを取得して、それを別のコードに変換します。その変換の一部として、それらはそのコードをより多くのコードで囲む場合があります。元のコードが変数aを参照し、その周りに追加されたコードがの新しいバージョンを定義している場合a、間違ったアクセスを行うため、元のコードは期待どおりに機能しませんa:if

(myfunc a)

は元のコードでありa、整数であると想定されており、マクロはそれを取得して次のようXに変換します。

(let ((a nil)) X)

その後、マクロは正常に動作します

(myfunc b)

しかし、(myfunc a)に変換されます

(let ((a nil)) (myfunc a))

期待する整数ではなくmyfuncに適用されるため、これは機能しません。nil

衛生的なマクロは、使用される名前が一意であることを確認することにより、間違った変数がアクセスされるというこの問題(およびその逆の同様の問題)を回避します。

ウィキペディアには、衛生的なマクロについての優れた説明があります。

于 2010-06-09T22:59:19.620 に答える
2

言及されたすべてのものとは別に、Schemeの衛生的マクロには、字句スコープに続く重要なものが1つあります。

私たちが持っていると言う:

(syntax-rules () ((_ a b) (+ a b)))

マクロの一部として、確かに+を挿入します。また、+がすでに存在する場合にも挿入しますが、。と同じ意味を持つ別の記号を挿入し+ます。シンボルを、syntax-rulesそれが適用される場所ではなく、嘘が存在する字句環境で持っていた値にバインドします。結局、字句スコープが適用されます。+ほとんどの場合、そこに完全に新しいシンボルが挿入されますが、マクロが定義されている場所と同じ意味にグローバルにバインドされているシンボルです。これは、次のような構成を使用する場合に最も便利です。

(let ((+ *))
  ; piece of code that is transformed
)

したがって、マクロの作成者またはユーザーは、その使用がうまくいくことを保証することに専念する必要はありません。

于 2010-06-10T22:33:49.730 に答える