首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >方案宏扩展:在define-syntax内嵌套let-语法

方案宏扩展:在define-syntax内嵌套let-语法
EN

Stack Overflow用户
提问于 2012-01-24 21:46:56
回答 1查看 1.3K关注 0票数 1

我想扩展一下

代码语言:javascript
复制
(foo x (f n) (f n) (arbitrary) (f n) ...)

转到

代码语言:javascript
复制
(begin (x 'f n) (x 'f n) (arbitrary) (x 'f n) ...)

我的尝试是:

代码语言:javascript
复制
(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))

使用宏步进程序,我可以看到宏的第一阶段展开为

代码语言:javascript
复制
(let-syntax ((f (syntax-rules () ((_ n) (x 'f n)))))
  (begin (f 1) (f 2) (arbitrary) (f 3)))

当单独评估时,它可以很好地工作,但当作为一个整体执行时,我得到一个错误,即f是一个未定义的标识符。我假设这是作用域中的一个问题,这种类型的宏扩展可能吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-01-24 22:23:46

是的,您需要从某个地方获取f --您的宏只是虚构的,因此它对foo用户是不可见的。当你确实认为你需要从某个地方获得它时,问题是你会从哪里获得它?下面是代码的一个修复版本,它假定它是foo的第二个子表单中的第一个内容

代码语言:javascript
复制
(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,以查看所有表单都被转换了。)

但是,如果您希望在foo中使用全局类型的f,那么您实际上必须这样做:定义一个全局f。下面是一种有限的方法:

代码语言:javascript
复制
;; 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时,它才能工作--但是如果它嵌套在表达式中,它就不能工作。例如,这将抛出语法错误:

代码语言:javascript
复制
(foo x (f 1) (f 2) (arbitrary)
       (let ([n 3]) (f n)))

您可以想象使foo-helper变得复杂并让它递归地扫描其输入,但这是一个您不想陷入的滑坡路。(您需要为quote内部、绑定中等位置设置特殊情况)

在球拍中(最近在Guile中也是如此)解决这个问题的方法是使用syntax parameter。可以将其视为使用define-syntax-parameterf绑定到同一无用的宏,然后使用syntax-parameterize将其在foo中的含义“调整”为执行所需转换的宏。这看起来是这样的:

代码语言:javascript
复制
;; 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)))
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8987869

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档