这是一个非常简单的Scheme宏,可以在MIT/GNU Scheme 12.1上运行:
1 ]=> (define-syntax example
(syntax-rules ()
((_) 'ok)))
;Value: example
1 ]=> (example)
;Value: ok
但是,使用名称
if
定义相同的宏会产生错误:
1 ]=> (define-syntax if
(syntax-rules ()
((_) 'ok)))
;Premature reference to reserved name: if
;To continue, call RESTART with an option number:
; (RESTART 1) => Return to read-eval-print level 1.
我以前从未使用过Scheme宏,但我的印象是Scheme没有“保留”名称,并且Scheme中的任何名称都可以重新定义。事实上,将
if
重新定义为正常程序可以按预期工作:
1 ]=> (define (if) 'ok)
;Value: if
1 ]=> (if)
;Value: ok
我浏览了参考手册中有关宏的部分(https://www.gnu.org/software/mit-scheme/documentation/stable/mit-scheme-ref/Macros.html),但我不能'找不到问题的原因。
是否有
syntax-rules
的内部操作导致此失败?
更新1
使用
if
本地重新定义 let-syntax
有效:
1 ]=> (let-syntax ((if (syntax-rules () ((_) 'ok))))
(if))
;Value: ok
我仍然不确定为什么
define-syntax
不起作用。
更新2
可以使用宏隐藏其他内置关键字:
1 ]=> (define-syntax define (syntax-rules () ((_) 'ok)))
;Value: define
1 ]=> (define)
;Value: ok
1 ]=> (define-syntax set! (syntax-rules () ((_) 'ok)))
;Value: set!
1 ]=> (set!)
;Value: ok
1 ]=> (define-syntax lambda (syntax-rules () ((_) 'ok)))
;Value: lambda
1 ]=> (lambda)
;Value: ok
1 ]=> (define-syntax cond (syntax-rules () ((_) 'ok)))
;Value: cond
1 ]=> (cond)
;Value: ok
有趣的是,你甚至可以重新定义
define-syntax
:
1 ]=> (define-syntax define-syntax (syntax-rules () ((_) 'ok)))
;Value: define-syntax
1 ]=> (define-syntax)
;Value: ok
但是,尝试重新定义关键字
syntax-rules
会遇到与重新定义 if
类似的错误(注意:我启动了一个新的 REPL,因为最后一个宏被遮蔽了 define-syntax
):
1 ]=> (define-syntax syntax-rules (syntax-rules () ((_) 'ok)))
;Premature reference to reserved name: syntax-rules
;To continue, call RESTART with an option number:
; (RESTART 1) => Return to read-eval-print level 1.
if
can 在许多Scheme 实现中被定义为顶层的宏。我测试过
(define-syntax if
(syntax-rules ()
((_) 'ok)))
(ok) ; returns 'ok
关于 Guile 3.0.9、Chicken 5.3.0、Gauche 0.9.9、Chibi 0.10.0(以 git 最新版本的形式)、Chez 9.6.2、Gambit 4.9.5、Kawa 3.1.1 和 MIT/ GNU 方案 11.2。所有人都接受并运行代码,没有错误。您说您正在使用 MIT/GNU 方案 12.1,因此两个版本之间的某些更改是有原因的。
有趣的是,
syntax-rules
的重新定义给出了11.2中的错误。 Guile、Chicken、Gauche、Chibi 和 Gambit 都接受了,而 Chez 和 Kawa 则抛出了错误。