我希望扩展
(foo x (f n) (f n) (arbitrary) (f n) ...)
到
(begin (x 'f n) (x 'f n) (arbitrary) (x 'f n) ...)
我的尝试是:
(define-syntax foo
(syntax-rules ()
((_ l a ...)
(let-syntax ((f (syntax-rules ()
((_ n) (l (quote f) n)))))
(begin a ...)))))
(define (x t1 t2) (cons t1 t2)) ;; for example only
(define (arbitrary) (cons 'a 'b)) ;; for example only
(foo x (f 1) (f 2) (arbitrary) (f 3))
使用宏步进器我可以看到宏的第一阶段扩展为
(let-syntax ((f (syntax-rules () ((_ n) (x 'f n)))))
(begin (f 1) (f 2) (arbitrary) (f 3)))
其中,当在隔离中进行评估时效果很好,但是当作为一个整体执行时,我得到一个关于f
是未定义标识符的错误。我认为这是范围界定中的一个问题,这种宏扩展是否可能?
答案 0 :(得分:3)
是的,您需要从某处获取f
- 您的宏只是弥补它,因此foo
的用户看不到它。当你考虑到你需要从某个地方获得它时,问题是你从哪里得到它?这是代码的固定版本,它假定它是foo
的第二个子表单中的第一个:
(define-syntax foo
(syntax-rules ()
[(_ l (f a) more ...)
(let-syntax ([f (syntax-rules ()
[(_ n) (l 'f n)])])
(list (f a) more ...))]))
(define (x t1 t2) (cons t1 t2))
(define (arbitrary) (cons 'a 'b))
(foo x (f 1) (f 2) (arbitrary) (f 3))
(我还将其扩展为list
以查看所有表单都已转换。)
但是,如果您希望在f
中使用全局foo
,那么您必须这样做:定义全局f
。这是一种有限的方式:
;; no body => using `f' is always an error
(define-syntax f (syntax-rules ()))
(define-syntax foo
(syntax-rules ()
[(_ l a ...) (list (foo-helper l a) ...)]))
(define-syntax foo-helper
(syntax-rules (f) ; match on f and transform it
[(_ l (f n)) (l 'f n)]
[(_ l a) a]))
(define (x t1 t2) (cons t1 t2))
(define (arbitrary) (cons 'a 'b))
(foo x (f 1) (f 2) (arbitrary) (f 3))
这方面的主要限制是它只有在a
表单之一使用f
时才有效 - 但如果它嵌套在表达式中则不起作用。例如,这将引发语法错误:
(foo x (f 1) (f 2) (arbitrary)
(let ([n 3]) (f n)))
你可以想象使foo-helper
复杂化并使其以递归方式扫描其输入,但这是一个你不想进入的滑坡。 (您需要为quote
内部,绑定等场所制作特殊情况。)
在Racket(以及最近在Guile中)解决这个问题的方法是使用syntax parameter。将此视为使用define-syntax-parameter
将f
绑定到相同的无用宏,然后使用syntax-parameterize
将其在foo
内的含义“调整”为执行转换的宏你要的那个。这是这样的:
;; needed to get syntax parameters
(require racket/stxparam)
;; same useless definition, but as a syntax parameter
(define-syntax-parameter f (syntax-rules ()))
(define-syntax foo
(syntax-rules ()
[(_ l a ...)
;; adjust it inside these forms
(syntax-parameterize ([f (syntax-rules ()
[(_ n) (l 'f n)])])
(list a ...))]))
(define (x t1 t2) (cons t1 t2))
(define (arbitrary) (cons 'a 'b))
(foo x (f 1) (f 2) (arbitrary)
(let ([n 3]) (f n)))