我仍然对这个概念有些麻烦。 r7rs标准中的关键段落是:
“出现在模板中但不是模式的标识符
变量或标识符ellipsis
作为文字标识符插入到输出中。如果将文字标识符插入为
免费标识符,则它指的是该标识符的绑定
在其范围内出现语法规则的实例。
如果将文字标识符作为绑定标识符插入,则
实际上,已对其重命名以防止意外捕获
免费标识符。”
“绑定标识符”是对的,它表示lambda
,顶级define
或语法定义的任何参数。 define-syntax
,let-syntax
或let-rec-syntax
? (我认为我可以在编译时将内部define
处理为技巧,将它们转换为lambda。)
“免费标识符”是否意味着任何其他事先用“绑定标识符”表达式定义的标识符?
我想知道这样的代码输出:
(define x 42)
(define-syntax double syntax-rules ()
((_) ((lambda () (+ x x)))))
(set! x 3)
(double)
结果应该是84还是6?
那呢:
(define x 42)
(define-syntax double syntax-rules ()
((_) ((lambda () (+ x x)))))
(define (proc)
(define x 3)
(double))
(proc)
我是否应该假设,由于define-syntax
出现在顶层,因此它的所有自由引用都指向在定义时可能存在或不存在的顶层变量。因此,为避免在使用时与局部变量发生冲突,我们应重命名输出的自由引用,例如在名称后添加“%”(并禁止用户创建其中包含%的符号)。除了重复引用顶级变量外,这次还添加了%。
如果以某种形式的嵌套作用域(使用let-syntax
或let-rec-syntax
定义宏,则如果它引用作用域变量,则将更加棘手。使用宏时,必须在宏定义点而不是使用点将这些引用扩展为它们的形式。因此,我猜测最好的方法是自然扩展它并扫描结果lambda
,如果找到一个,按照r7rs的建议在定义点重命名其参数。但是,此lambda内部的引用又该如何更改呢?这似乎很明显,但在标准中并未明确说明。
我仍然不确定是否最好将一个单独的扩展阶段与编译器分开,或者将扩展宏与编译代码交织在一起。
谢谢,如果我显然错过了一些新手,请原谅。
史蒂夫
答案 0 :(得分:1)
在第一个示例中,正确编写:
(define x 42)
(define-syntax double
(syntax-rules ()
( (_) ((lambda () (+ x x))) ) ))
(set! x 3)
(double)
the only possibility is 6,因为只有一个变量称为x
。
在第二个示例中,正确编写:
(define x 42)
(define-syntax double
(syntax-rules ()
((_) ((lambda () (+ x x))) )))
(define (proc)
(define x 3)
(double))
(proc)
Scheme宏系统的卫生性质阻止了无关的本地x
,因此the result is 84的捕获。
通常,语法规则中的标识符(如您的x
)是指它们在词汇上引用的内容(在您的情况下为全局x
)。由于卫生,这种结合将得以保留。由于卫生,您不必担心意外捕获。
答案 1 :(得分:0)
谢谢,我想我了解...我仍然想知道在某些高级情况下如何实现卫生,例如。以下:
(define (myproc x)
(let-syntax ((double (syntax-rules ()
((double) (+ x x)))))
((lambda (x) (double)) 3)))
(myproc 42)
该网站的得分是84,而不是6。我想知道仅通过重命名就可以实现这种(正确的)参照透明性。转换器的输出不绑定新变量,但是在第4行上进行扩展时,我们仍然必须找到一种方法来获得所需的x
而不是最新的变量。
我能想到的最好的方法是,每当一个lambda参数或定义隐藏另一个参数时,即每次重命名。继续追加%1
,%2
等...宏输出将使用其确切版本命名(例如x%1
),而对标识符的引用仅具有其未经修饰的名称x
,并且在编译时找到正确的变量。
谢谢,我希望得到澄清。
史蒂夫