这些例子显示了 syntax-rules 里面最容易搞混淆的地方。
(define mydef "mydef defined in toplevel") (define aa 5) (define-syntax test-macro (syntax-rules (mydef) ((_) #f) ((_ mydef bar st1 st2 ...) (letrec ((bar (lambda () (display "this is: ") (display bar) (newline) (display "mydef is bound to: ") (display mydef) (newline)))) st1 st2 ...)) ((_ e1 e2 e3 ...) (let ((t e1)) (display "aa's value is: ") (display aa) (newline) (if t t (or e2 e3 ...)))))) (test-macro mydef foo (foo)) (test-macro mydef bar (bar))
结果是:
> this is: #<procedure:foo> mydef is bound to: mydef defined in toplevel > this is: #<procedure:bar> mydef is bound to: mydef defined in toplevel
这里显示了:
接下来:
(let ((mydef "mydef defined in let")) (test-macro mydef bar (bar)))
结果是:
> aa's value is: aa defined in toplevel "mydef defined in let"
这个例子显示了:
接下来:
(define mydef #f) (test-macro mydef bar (bar))
结果是:
> this is: #<procedure:bar> mydef is bound to: #f
这说明,literal mydef 仍然匹配,虽然它们的顶层定义改变了。
接下来我们把 test-macro 定义在一个 let 块里:
(let ((mydef "mydef defined in syntax block") (aa "aa in outer syntax block")) (define-syntax test-macro (syntax-rules (mydef) ((_) #f) ((_ mydef bar st1 st2 ...) (letrec ((bar (lambda () (display "this is: ") (display bar) (newline) (display "mydef is bound to: ") (display mydef) (newline)))) st1 st2 ...)) ((_ e1 e2 e3 ...) (let ((t e1)) (display "aa's value is: ") (display aa) (newline) (if t t (or e2 e3 ...)))))) (test-macro mydef bar (bar)) (let ((mydef "mydef defined in inner let") (aa "aa defined in inner let block")) (test-macro mydef bar (bar))) ) (set! aa "aa definition changed in outer let") (let ((mydef "mydef defined in inner let") (aa "aa defined in inner let block")) (test-macro mydef bar (bar))) )
结果是:
> this is: #<procedure:bar> mydef is bound to: mydef defined in syntax block aa's value is: aa in outer syntax block aa's value is: aa definition changed in outer let "mydef defined in inner let"
这说明:
接下来:
(let ((aa 6) (mydef "mydef in let block")) (test-macro mydef bar (bar)))
结果是:
> aa's value is: aa defined in toplevel "mydef in let block"
虽然在 let 内重新绑定了 aa 的值,但是由于这时我们使用的是最 外层定义的语法 test-macro, 所以它的 aa 引用的是最外层的 aa.
重新定义 test-macro, 不把 mydef 作为 literal.
(define-syntax test-macro (syntax-rules () ((_) #f) ((_ mydef bar st1 st2 ...) (letrec ((bar (lambda () (display "this is: ") (display bar) (newline) (display "mydef is bound to: ") (display mydef) (newline)))) st1 st2 ...)) ((_ e1 e2 e3 ...) (let ((t e1)) (display "aa's value is: ") (display aa) (newline) (if t t (or e2 e3 ...)))))) (let ((mydef "mydef defined in let")) (test-macro mydef bar (bar)))
结果是:
> this is: #<procedure:bar> mydef is bound to: mydef defined in let
这个例子里的 mydef 不是一个 literal,所以它即使在 let 内部重 新绑定,仍然可以匹配。而且它的值是重新绑定以后的值。
这就让我想起 R5RS 里的例子:
(let ((=> #f)) (cond (#t => 'ok)))
结果是 ok. 这里 => 虽然在内部被重新绑定。但是 cond 是在顶层 定义的,所以只有顶层定义的 => 才能匹配这个 "=>".
所以
(cond (#t => 'ok))
无论你是否在顶层重新定义 => 都是要出错的。