这是一个非常简单的可运行的Scheme宏,运行在MIT/GNUScheme 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
可以在许多方案实现中定义为顶层的宏。我测试过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 则抛出了错误。