定义和让w.r.t之间的区别。 syntax-rules关键字

时间:2016-06-05 17:05:02

标签: macros scheme racket

我是Racket和Lisp的初学者,正在玩语法定义。我定义了一个像这样的简单转换:

(define-syntax hello
  (syntax-rules (in)
    ((_ name in world) (format "Hello ~a in ~a" name world))
    ((_ in name) (format "Hello ~a in here" name))))

现在,当我像这两种情况一样运行它时,它运行正常:

(hello "me" in "world") === "Hello me in world"

(define in "inside")
(hello me in in)  === "Hello me in inside"

但是,这会导致错误,

(let ([in "Shire"])
  (hello "Martin" in in)) === Error: hello: bad syntax in: (hello "Martin" in in)

那么,hello在let绑定中失败的原因是什么,而它适用于定义?另外,我在哪里可以获得有关这种差异的更具体信息?感谢。

2 个答案:

答案 0 :(得分:4)

这与语法文字的工作方式有关。特别是,在以下情况下,语法文字被视为匹配:

  1. 文字在宏定义时没有绑定,并且在宏使用时也没有绑定。
  2. 文字在宏定义时具有绑定,并且在宏使用时具有相同的绑定
  3. define案例对您有用,因为您可能将define放在与宏相同的模块中。这意味着匹配的条件2:in在宏定义和使用方面具有相同的绑定。但是,如果您在一个模块中定义了宏(define没有in),并且在您使用宏的其他模块中定义了in,那么事情就会赢得。工作得很好。 : - )

    let案例为in创建了新的约束。这将永远不会匹配顶级宏定义中in的绑定。

答案 1 :(得分:3)

原因有点微妙 - 既不“应该”有效,但当define处于顶层时,它实际上改变对{{1}的解释},这是行为产生的地方。

如果您查看the documentation for syntax-rules,您会发现每个 syntax-rules 的处理方式与syntax-case中的相同。该文档指出使用literal-id

比较文字
  

free-identifier=? 具有相同绑定的 id 匹配语法对象,该语法对象是具有相同绑定的标识符free-identifier=?

这意味着文字与绑定匹配,而不是作为基准。也就是说,如果您在literal-id中有in的本地定义,则它与let中标记为文字的in分开绑定,因此它们不会比赛。此外,在单独模块中使用syntax-rules引入的标识符也不匹配。

有趣的是,如果define从定义宏的模块导出,然后使用in导入,则重命名的绑定仍然有效,因为Racket会跟踪重命名并认为它们是相同的绑定即使它们不是同名。这些都是正交的概念,即使它有时很容易忽视这个想法的所有细微差别,但它有点内在于卫生。

回到相关示例,为什么以下工作?

rename-in

嗯,定义上下文是相互递归,因此宏定义后(define-syntax hello (syntax-rules (in) ((_ name in world) (format "Hello ~a in ~a" name world)) ((_ in name) (format "Hello ~a in here" name)))) (define in "inside") (hello "me" in in) 的定义实际上被in选中。因此,syntax-rules宏实际上需要与hello相同的绑定,因此调用有效。但是,如果in在与hello不同的模块中定义,则宏调用将,因为绑定会有所不同:

in