Scheme中的宏和内部定义



在Freenode的#scheme频道上提出了一个很好的问题。在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 )

betagammadelta中的哪一个应该产生语法错误?哪个?我已经用赤壁方案检查了这一点,其中beta很好,而gammadelta失败。我不知道这是有意为之,还是赤壁的一个bug。

根据该标准,似乎应该在内部定义重写为letrec*之前扩展宏。因此betagamma都应该失败,因为foo将与内部定义的alpha匹配,而不是全局的。

然而,标准中并没有明确规定内部定义的实际工作方式,只是它们可以被视为letrec快捷方式。我对Racket的R5RS也有同样的行为,所以我似乎在标准中缺少了一些要求这种行为的东西。

好的,我终于明白你的问题了。运行您的代码很有挑战性,因为您似乎有一个"语法错误"函数,只有当它最终以完全展开的代码结束时,它才会发出语法错误的信号。无论什么

我认为你的问题的答案是:

这些Scheme的家伙(Dybvig、Felleisen、Hieb、Clinger、Rees、Wand、Flatt、Culpepper等)都很聪明!

特别是,Scheme/Racket设法弄清楚绑定结构是如何工作的,即使它不知道什么将是绑定或不是绑定。你说得对!太疯狂了!但Dybvig等人概述的算法做了一些非常聪明的事情,以确保卫生跟踪标识符是"自由标识符相等"还是"绑定标识符相等"(Flatt的术语),即使它还不知道哪一个绑定另一个。我个人建议阅读"一起工作的宏"(Flatt,Culpepper,Darais,Findler),以更好地理解这一点。

如果我误解了你的问题,或者我的语气不恰当,请道歉!

可能有点太多,这取决于实现端,但这种行为是因为宏扩展的顺序。从理论上讲,所有的定义都包含alpha,所以它不应该和文字关键字中的定义相匹配。然而,在将define形式扩展到letrec*之前,需要进行宏扩展,否则编译器无法正确检测内部定义。所以在那个时刻,编译器可能看到绑定,也可能看不到绑定。(宏扩展时序是,而不是R7RS上指定的,因此实现也可以选择自己的时序。)

对于beta的情况,编译器没有捕捉到绑定,所以宏扩展器仍然可以看到alpha是与全局绑定相同的绑定。其他情况则相反。

首先,delta已退出(不应与alpha匹配),因为它在词汇上清楚地将alpha绑定到另一个绑定,而不是出现sytnax-rules的绑定。有趣的是CCD_ 21和CCD_。

根据第5.2.2节。R4RS(第13页)和R5RS(第16页),第5.3.2节。R7RS(第26页),以及第11.3节。在R6RS(第32页)中,通过内部定义建立的结合的"区域"是该定义出现的整个<body>。对foo的宏调用显然与那些内部定义在相同的<body>中。

R7RS还进一步警告我们:

请注意,这样的主体[即包含内部定义的主体]可能在扩展其他语法之后才会显现出来。

因此,混乱的事件顺序被承认,但没有歧义;如果在调用宏的同一<body>中有任何内部定义对alpha的绑定,则syntax-rules不应与alpha分支匹配因此,betagamma也出局

附录A

如果我们进一步使情况复杂化,并且您的宏本身有条件地绑定alpha,就像一样

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

乍一看,这似乎真的很模糊,但我相信这是通过以下事实解决的:宏扩展器将根据卫生条件重命名定义的alpha标识符,这意味着我们不会将匹配的alpha隐藏为文字,所以匹配它是可以的,上面的操作只会为重命名的alpha创建一个绑定,该绑定在宏体之外是不可访问的。

附录B

第5.3节末尾有一个限制。R5RS(第17页),第5.4节末尾。R7RS(第26页),以及第10节的中间部分。在R6RS(第30页)中,提到一系列定义不应包含改变其中任何定义含义的定义。(这实际上有点复杂,所有三个标准都使用了不同的措辞,但这应该是一个合理的总结。)

在您的例子中,我不清楚您的syntax-rules扩展为语法错误的可能性是否算作其"含义"的歧义。如果认为这是歧义,那么根据R5RS和R7RS,您的betagamma是"错误"(未定义行为),根据R6RS,则是"语法违规"。

如果您的示例在syntax-rules的第二个分支中包含另一个绑定(理想情况下甚至是同一变量的定义),那么这个挑剔的问题将不适用,因此您的问题仍然存在。

相关内容

  • 没有找到相关文章

最新更新