我正在尝试编写模式匹配宏。我没有走得太远,但我已经困惑了。我的测试代码如下
#!r6rs
(import (for (rnrs base (6)) run expand)
(for (rnrs syntax-case (6)) expand)
(rnrs io simple (6)))
(define-syntax matcher
(lambda (stx)
(define (parse-clauses c)
#'x)
(syntax-case stx ()
((_ c ...)
(with-syntax ((body (parse-clauses #'(c ...))))
#'(lambda (x) body))))))
(write ((matcher) '(1 2 3))) (newline)
执行此操作会生成输出(1 2 3)
。
说实话,我写这段代码的期望是它会失败。我认为从parse-clauses
返回的语法是指未定义的符号x
。但似乎从#'x
返回的parse-clauses
确实引用了lambda表达式中的参数x
。我不知道为什么。
这种微小的变化使我更加困惑。
#!r6rs
(import (for (rnrs base (6)) run expand)
(for (rnrs syntax-case (6)) expand)
(rnrs io simple (6)))
(define-syntax matcher
(lambda (stx)
(define (parse-clauses c)
(let ((x 1))
#'x))
(syntax-case stx ()
((_ c ...)
(with-syntax ((body (parse-clauses #'(c ...))))
#'(lambda (x) body))))))
(write ((matcher) '(1 2 3))) (newline)
这会产生错误x: identifier used out of context in: x
。我理解这个错误,x
在parse-clauses
本地绑定,但我在该范围之外使用引用,所以我收到错误。
我想我所说的是第二个例子表明词汇上下文很重要,但在第一个例子中,x
没有词法绑定,那么它最终如何引用一个不相关的绑定呢? / p>
我希望不要太困惑,欢迎任何解释。
我正在使用Racket 5.3.6。
答案 0 :(得分:0)
x
引用lambda参数,因为它们都是由相同的宏扩展步骤引入的 - 宏系统仅区分不同步骤引入的标识符(如果此宏扩展为引入另一个的另一个宏{ {1}},它将是一个不同的。)
我认为第二个错误是因为x
被绑定为编译时变量(x
是编译时函数)并且它以某种方式干扰了lambda中的parse-clauses