5

Freenode の #scheme チャンネルで良い質問が寄せられました。スキームで次のコードを検討してください。

(define alpha 1)

(define-syntax foo
  (syntax-rules (quote alpha)
    ((_ alpha msg) (define bar 2))
    ((_ other msg) (syntax-error msg)) ) )

(define (beta)
  (foo alpha "beta")
  (define alpha 3)
  'beta )

(define (gamma)
  (define alpha 4)
  (foo alpha "gamma")
  'gamma )

(define (delta alpha)
  (foo alpha "delta")
  'delta )

betagamma、およびのうち、delta構文エラーが発生するのはどれですか? そして、どちらですか私はこれをちびスキームでチェックしましbetaた。これは意図した動作なのか、Chibi の単なるバグなのか疑問に思います。gammadelta

標準によると、マクロの展開は、内部定義が に書き換えられる前に行われるべきであると思われletrec*ます。したがってbeta、グローバルなものではなく、内部的に定義された と一致するため、gamma両方とも失敗するはずです。fooalpha

ただし、内部定義が実際にどのように機能するかは標準では明示的に指定されておらず、letrec のショートカットとして考えられるだけです。Racket の R5RS で同じ動作が得られるため、そのような動作を要求する標準に何かが欠けているようです。

4

3 に答える 3

1

わかりました、ようやくあなたの質問を理解しました。完全に展開されたコードになった場合にのみ構文エラーを通知する「構文エラー」関数があるように見えるため、コードの実行は困難でした。なんでもいい。

あなたの質問に対する答えはこれだと思います:

これらの Scheme の連中 (Dybvig、Felleisen、Hieb、Clinger、Rees、Wand、Flatt、Culpepper など) はかなり賢いです!

特に、どういうわけか、Scheme/Racket は、何がバインディングになるかどうかわからない場合でも、バインディング構造がどのように機能するかを把握することができます。あなたが正しい!それはクレイジーです!しかし、Dybvigらによって概説されたアルゴリズム。どちらが他の識別子をバインドしているのかまだわからない場合でも、識別子が「free-identifier-equal」または「bound-identifier-equal」(Flatt の用語) であるかどうかを衛生管理が確実に追跡するように、いくつかの非常に巧妙な処理を行います。個人的には、これをよりよく理解するために、"Macros That Work Together" (Flatt、Culpepper、Darais、Findler) を読むことをお勧めします。

私があなたの質問を誤解していたり​​、私の口調が不適切だったりした場合は、申し訳ありません!

于 2014-09-24T15:49:14.070 に答える
1

実装側によっては多すぎるかもしれませんが、この動作はマクロ展開の順序によるものです。理論的には、すべての定義に含まれalphaているため、リテラル キーワードの定義とは一致しないはずです。defineただし、フォームが に展開される前にマクロ展開を行う必要がありletrec*ます。そうしないと、コンパイラは内部定義を適切に検出できません。したがって、その時点で、コンパイラはバインディングを認識できる場合と認識できない場合があります。(R7RSではマクロ展開のタイミングは規定されていないので、実装も独自のタイミングを選ぶかもしれません。)

このbeta場合、コンパイラはバインディングをキャッチしなかったため、マクロ エキスパンダーはそれalphaがグローバル バインディングと同じバインディングであることを認識できます。他のケースは逆です。

于 2015-02-09T15:33:56.143 に答える
0

まず第一に、あなたが現れるバインディングとは別のバインディングに明らかにレキシカルにバインドされるため、deltaアウトです(一致するべきではありません)。興味深いのはとです。alphaalphasytnax-rulesbetagamma

セクション 5.2.2 に従って。R4RS (p. 13) および R5RS (p. 16) のセクション 5.3.2。R7RS の (p. 26)、およびセクション 11.3。R6RS (p. 32) では、内部定義によって確立されたバインディングの「領域」は、<body>定義が現れる全体です。そして、あなたのマクロ呼び出しfooは明らかに<body>それらの内部定義と同じです。

R7RS はさらに進んで、次のように警告しています。

そのような本体 [つまり、内部定義を含むもの] は、他の構文の展開後まで明らかにならない可能性があることに注意してください。

したがって、イベントの順序がめちゃくちゃであることは認められますが、あいまいさはありません。マクロの呼び出しと 同じ内部定義によるバインディングがある場合syntax-rulesは、ブランチと一致しないでください。したがって、およびもアウトです。alphaalpha<body>betagamma

付録 A

状況がさらに複雑になり、マクロ自体が条件付きでバインドされたalpha場合、

(syntax-rules (alpha)
  ((_ alpha x) (define alpha x)))

最初の考えでは本当にあいまいに思えますが、これは、マクロ エキスパンダーが定義された識別子の名前を衛生的に変更するという事実によって解決されると思いますalphaalpha上記はalpha、マクロ本体の外では到達できない、名前が変更された のバインドを作成するだけです。

付録 B

セクション 5.3 の最後に制約があります。R5RS の (p. 17)、セクション 5.4 の終わり。R7RS (p. 26) のセクション 10. の中間 (p. 30) では、一連の定義には、それらの意味を変更する定義を含めてはならないことが記載されています。(実際にはもう少し複雑で、3 つの標準すべてで異なる言葉遣いが使用されていますが、これは妥当な要約です。)

syntax-rulesあなたの例では、構文エラーに拡大する可能性がその「意味」のあいまいさと見なされるかどうかは明確ではありません。あいまいだと考えると、betaandgammaは R5RS と R7RS では「エラー」(未定義の動作) であり、R6RS では「構文違反」です。

あなたの例の2番目のブランチに別のバインディングが含まれていた場合syntax-rules(理想的には同じ変数の定義であっても)、このニッチは適用されないため、質問は有効です。

于 2015-05-29T14:50:33.843 に答える