【问题标题】:Macros and internal definitions in SchemeScheme 中的宏和内部定义
【发布时间】:2014-11-18 07:37:53
【问题描述】:

在 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 中的哪一个会产生语法错误?哪个?我已经使用 Chibi Scheme 进行了检查,其中 beta 很好,而 gammadelta 失败。我想知道这是有意的行为还是只是 Chibi 中的一个错误。

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

然而,标准内部定义如何实际工作并没有明确规定,只是它们可以被认为是letrec快捷方式。我在 Racket 的 R5RS 上得到了相同的行为,所以我似乎在标准中遗漏了一些需要这种行为的东西。

【问题讨论】:

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

标签: macros scheme r7rs


【解决方案1】:

好的,我终于明白你的问题了。运行你的代码很有挑战性,因为你似乎有一个“语法错误”函数,只有当它以完全扩展的代码结束时才会发出语法错误信号。随便。

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      首先,delta 已失效(不应匹配alpha),因为它在词法上明确地将alpha 绑定到另一个绑定,而不是您的sytnax-rules 出现的绑定。有趣的是betagamma

      根据第 5.2.2 节。 R4RS (p. 13) 和 R5RS (p. 16),第 5.3.2 节。 R7RS(第 26 页)和第 11.3 节。在 R6RS (p. 32) 中,通过内部定义建立的绑定的“区域”是定义出现的整个 <body>。您对foo 的宏调用显然与那些内部定义在同一个<body> 内。

      R7RS 也更进一步,警告我们:

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

      因此,混乱的事件顺序得到承认,但没有歧义;如果与宏的调用相同的<body> 中的任何内部定义对alpha 进行了绑定,则您的syntax-rules 不应匹配alpha 分支。 因此,betagamma 也被淘汰了。

      附录 A

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

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

      乍一看似乎确实模棱两可,但我相信通过宏扩展器将根据卫生情况重命名定义的alpha标识符这一事实解决了这个问题,这意味着我们不会隐藏alpha。匹配为文字,所以匹配它很好,上面将简单地为重命名的alpha 创建一个绑定,在宏体之外无法访问。

      附录 B

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

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

      如果您的示例在您的 syntax-rules 的第二个分支中包含另一个绑定(理想情况下甚至是同一变量的定义),那么这个 nitpick 将不适用,所以您的问题成立。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-22
        • 1970-01-01
        • 2014-03-15
        • 2012-10-24
        • 2013-12-01
        • 1970-01-01
        相关资源
        最近更新 更多