Macros Scheme中的宏和内部定义

Macros Scheme中的宏和内部定义,macros,scheme,r7rs,Macros,Scheme,R7rs,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

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 )
哪些
beta
gamma
delta
会产生语法错误?你喜欢哪一个?我已经用Chibi方案对此进行了检查,
beta
很好,而
gamma
delta
失败。我想知道这是一个有意的行为还是赤壁的一个错误

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

但是,标准中并未明确规定内部定义的实际工作方式,只是可以将其视为letrec快捷方式。我对Racket的R5R也有同样的行为,所以我似乎在要求这种行为的标准中遗漏了一些东西。

好的,我终于理解了你的问题。运行代码是一项挑战,因为您似乎有一个“syntax error”函数,只有当它在完全扩展的代码中结束时才发出语法错误信号。不管怎样

我想你的问题的答案是:

这些阴谋家(戴维格、费莱森、希布、克林格、里斯、旺德、弗拉特、卡佩珀等)非常聪明

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


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

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


对于
beta
情况,编译器没有捕获绑定,因此宏扩展器仍然可以看到
alpha
与全局绑定相同。其他情况正好相反。

首先,
delta
不存在(不应匹配
alpha
),因为它在词汇上明确地将
alpha
绑定到另一个绑定,而不是出现
sytnax规则的绑定。有趣的是
beta
gamma

根据第5.2.2节。关于R4R(第13页)和R5R(第16页),第5.3.2节。R7RS(第26页)和第11.3节。在R6R中(第32页),通过内部定义建立的绑定的“区域”是定义出现的整个
。您对
foo
的宏调用显然与这些内部定义在同一个

R7RS还进一步警告我们:

请注意,这样的主体[即包含内部定义的主体]在扩展其他语法之前可能不明显

因此,混乱的事件顺序是可以接受的,但没有歧义;如果与宏调用相同的
中有任何内部定义对
alpha
的绑定,则您的
语法规则不应与
alpha
分支匹配因此,
beta
gamma
也被淘汰。

附录A

如果我们将情况进一步复杂化,并且宏本身有条件地绑定到alpha,如

(syntax-rules (alpha)
  ((_ alpha x) (define alpha x)))
然后,乍一看它似乎真的模棱两可,但我相信通过宏扩展器将根据卫生标准重命名定义的
alpha
标识符这一事实,这就解决了这一问题,这意味着我们不会跟踪我们作为文本匹配的
alpha
,因此匹配它很好,上面的代码将为重命名的
alpha
创建一个绑定,该绑定在宏体之外是不可访问的

附录B

第5.3节末尾有一个约束条件。关于R5R(第17页),第5.4节结束。第26页,第10节的中间部分。在R6RS(第30页)中,提到一系列定义不应包含改变任何定义含义的定义。(事实上,这有点复杂,三个标准都使用了不同的措辞,但这应该是一个合理的总结。)

在你的例子中,我不清楚你的
语法规则
扩展为语法错误的可能性是否算作对其“含义”的歧义。如果你认为它是歧义,那么你的
beta
gamma
根据R5RS和R7RS是“错误”(未定义的行为),并且是“语法冲突”根据R6RS

如果您的示例在
语法规则的第二个分支中包含了另一个绑定(理想情况下是对同一变量的定义),那么这个吹毛求疵的问题就不适用了。

在R6RS(基于psyntax的impl)中,我在调用过程时会得到同样的行为。