Macros Scheme中的宏和内部定义
Freenode的#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
(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)中,我在调用过程时会得到同样的行为。