这些例子显示了 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))
无论你是否在顶层重新定义 => 都是要出错的。