1

我想 展开

(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未定义标识符的错误。我认为这是范围界定的问题,这种类型的宏扩展可能吗?

4

1 回答 1

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))

(我还把它扩展成 alist以查看所有形式都被转换了。)

但是,如果您想在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并使其递归地扫描其输入,但这是您不想进入的滑坡。(您需要为 a 内quote、绑定内等地方制作特殊情况。)

在 Racket(以及最近在 Guile 中)解决这个问题的方法是使用语法参数。将此视为使用 绑定f到相同的无用宏define-syntax-parameter,然后使用syntax-parameterize将其在 a 中的含义“调整”为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)))
于 2012-01-24T14:23:46.227 回答