Macros define和let w.r.t.语法规则关键字之间的差异
我是一个初学者在球拍以及Lisp和玩语法定义。我定义了一个简单的转换,如下所示:Macros define和let w.r.t.语法规则关键字之间的差异,macros,scheme,racket,Macros,Scheme,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") ==
(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"
以及
但是,这会导致一个错误
(let ([in "Shire"])
(hello "Martin" in in)) === Error: hello: bad syntax in: (hello "Martin" in in)
那么,hello在let绑定中失败的原因是什么,而它在define中工作良好?另外,我在哪里可以获得关于这种差异的更具体的信息?谢谢。这与语法文字的工作方式有关。特别是,在以下情况下,语法文字被视为匹配:
define
案例适合您,因为您可能将define
与宏放在同一个模块中。这意味着标准2匹配:中的在宏定义和用法上具有相同的绑定。但是,如果您在一个模块中定义了宏(没有在
中为定义),并且在使用宏的另一个模块中定义了,事情就不会那么顺利了。:-)
let
案例为中的创建一个新绑定。这永远不会与顶级宏定义中的的绑定匹配。原因有点微妙,“应该”也不起作用,但当定义
处于顶级时,它实际上会改变语法规则的解释,这就是行为产生的原因
如果您查看,您将看到每个文字id
的处理方式与中相同。文档注意到,使用自由标识符=?
比较文本:
与literal id
具有相同绑定的id
与语法对象相匹配,该语法对象是具有相同绑定的标识符
这意味着文字是作为绑定匹配的,而不是作为基准匹配的。也就是说,如果在let
中有中的的本地定义,它是与中的在语法规则中标记为文字的单独绑定,因此它们将不匹配。此外,在单独模块中使用define
引入的标识符也将不匹配
有趣的是,如果从定义宏的模块导出
中的
,然后使用
中的
重命名导入,则重命名的绑定仍然有效,因为Racket跟踪重命名,并认为它们是相同的绑定,即使它们不是相同的名称。这些都是正交的概念,即使有时很容易忽略这个概念的所有细微差别,但这在某种程度上是卫生固有的
回到所讨论的例子,为什么下面的方法有效
(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)
嗯,定义上下文是相互递归的,因此在宏定义之后,
中的定义实际上是由语法规则
提取的。因此,hello
宏实际上需要与
中的相同的绑定,因此调用可以工作。但是,如果在与
中的不同的模块中定义了hello
,则宏调用将不起作用,因为绑定不同:
(module hello racket
(provide hello)
(define-syntax hello
(syntax-rules (in)
((_ name in world) (format "Hello ~a in ~a" name world))
((_ in name) (format "Hello ~a in here" name)))))
(require 'hello)
(define in "inside")
(hello "me" in in) ; => hello: bad syntax in: (hello "me" in in)
因此,如果我理解正确,则由于条件1,let
失败,即
中的绑定在宏使用期间存在,但在定义宏时不存在。但是,我仍然不清楚define
,因为在定义宏时也不存在这种绑定。我基本上在Racket的编辑器中定义了宏,运行它,然后通过REPL中的define
在
绑定中定义了。所以在这种情况下,第二个标准不应该匹配。或者我遗漏了什么?而且,当有一个全局定义时,这种情况也会发生。在函数中有一个(define n“something”)
,然后调用(hello“ok”in)
也会导致相同的错误。正如Alexis的回答所解释的,模块级define
影响模块中的所有内容(“相互递归”是她使用的措辞,但仍然是相同的含义),而不仅仅是后面的内容。对于函数中的内部define
,与模块级define
的处理方式不同。正确,在阅读Alexis的答案后,我重新阅读了您的答案,这是有意义的。谢谢。顺便说一句,我刚刚在IRC上看到你关于球拍的问题。你一定要坚持2分钟以上。IRC主要是一种潜在的媒体;如果您只发布实际问题(不等待任何人回复“有人能帮忙吗?”请求),然后等待24小时等待回复,您将获得最佳结果。:-)(但是,正如你所知道的,莱西·兰姆达和我都能在这里回答,所以这终究是可行的。)这就是原因。谢谢
(module hello racket
(provide hello)
(define-syntax hello
(syntax-rules (in)
((_ name in world) (format "Hello ~a in ~a" name world))
((_ in name) (format "Hello ~a in here" name)))))
(require 'hello)
(define in "inside")
(hello "me" in in) ; => hello: bad syntax in: (hello "me" in in)