Macros 如何使用模板宏重写此宏?
假设我想在Racket/Scheme中定义一个宏,该宏由instruments“定义”。具体地说,它计算define主体中的文本数,然后将该数字添加到所有这些文本中(这应该发生在宏扩展阶段) 以下是以普通函数样式定义的宏(以列表形式在语法树上操作): 我想用普通的Racket/Scheme模板宏样式重写它。以下是我的(不成功)尝试: 其思想是分阶段插入代码:首先标记语法树中的所有节点,然后计算文本,在需要时用“transform”宏替换标记。。。正如注释的“displays”所示,宏“mark”在所有“descent”完成之前开始扩展(因此它们仍然处于宏代码捕获的状态)。即使“display-counted-n”扩展得太快,而“n”仍然是0 有没有办法改变宏扩展的顺序?我希望Racket/Scheme分阶段进行扩展:首先是“下降”,然后是“标记”,然后是“变换”,然后是“显示-计数-n”Macros 如何使用模板宏重写此宏?,macros,scheme,racket,Macros,Scheme,Racket,假设我想在Racket/Scheme中定义一个宏,该宏由instruments“定义”。具体地说,它计算define主体中的文本数,然后将该数字添加到所有这些文本中(这应该发生在宏扩展阶段) 以下是以普通函数样式定义的宏(以列表形式在语法树上操作): 我想用普通的Racket/Scheme模板宏样式重写它。以下是我的(不成功)尝试: 其思想是分阶段插入代码:首先标记语法树中的所有节点,然后计算文本,在需要时用“transform”宏替换标记。。。正如注释的“displays”所示,宏“mark”
我已经阅读了的答案-似乎用模板宏实现这一任务的唯一方法是使用“秘密文本”,并在一个大宏定义中定义所有内容。然而,我想这会使代码更难编写和阅读。也许还有其他方法吗?这是我的
语法案例版本
宏版本:
(define-syntax (lambda-fun stx)
(define (count-numeric-literals stx2)
(syntax-case stx2 ()
(num (number? (syntax->datum #'num)) 1)
((first rest ...) (+ (count-numeric-literals #'first)
(count-numeric-literals #'(rest ...))))
(_ 0)))
(define (instrument-numeric-literals stx3 n)
(syntax-case stx3 ()
(num (number? (syntax->datum #'num))
(datum->syntax #'num (+ (syntax->datum #'num) n)))
((first rest ...)
(with-syntax ((a (instrument-numeric-literals #'first n))
((b ...) (instrument-numeric-literals #'(rest ...) n)))
#'(a b ...)))
(x #'x)))
(syntax-case stx ()
((_ params . body)
(let ((count (count-numeric-literals #'body)))
(with-syntax ((instrumented (instrument-numeric-literals #'body count)))
#'(lambda params . instrumented))))))
(define-syntax define-fun
(syntax-rules ()
((_ (f . params) . body)
(define f (lambda-fun params . body)))
((_ . passthrough)
(define . passthrough))))
这利用语法保护(也称为挡泥板)来决定语法数据是否为数字。为了便于阅读,您可以使用语法分析
,它允许您指定语法类,如数字
,而不是使用语法保护:
(require (for-syntax syntax/parse))
(define-syntax (lambda-fun stx)
(define (count-numeric-literals stx2)
(syntax-parse stx2
(num:number 1)
((first rest ...) (+ (count-numeric-literals #'first)
(count-numeric-literals #'(rest ...))))
(_ 0)))
(define (instrument-numeric-literals stx3 n)
(syntax-parse stx3
(num:number (datum->syntax #'num (+ (syntax->datum #'num) n)))
((first rest ...)
(with-syntax ((a (instrument-numeric-literals #'first n))
((b ...) (instrument-numeric-literals #'(rest ...) n)))
#'(a b ...)))
(x #'x)))
(syntax-parse stx
((_ params . body)
(let ((count (count-numeric-literals #'body)))
(with-syntax ((instrumented (instrument-numeric-literals #'body count)))
#'(lambda params . instrumented))))))
例如:
> (define-fun (fun) (+ 1 2 3 4))
> (fun)
26
谢谢你,克里斯。我将学习挡泥板和语法解析。。。如果我们不能使用#body(如上所述)的两个单独副本,该如何处理?例如,如果我们1)使用(generate temporary)生成的id-s插入语法树的(某些)节点;2) 必须以某种方式将这些id-s的列表转移到运行时。我不确定您实际上想做什么。您可能希望就此提出一个新问题,并详细说明您正在尝试做什么。:-)经过一番思考,我成功了。也许以后我会问一些新问题。谢谢。)
(require (for-syntax syntax/parse))
(define-syntax (lambda-fun stx)
(define (count-numeric-literals stx2)
(syntax-parse stx2
(num:number 1)
((first rest ...) (+ (count-numeric-literals #'first)
(count-numeric-literals #'(rest ...))))
(_ 0)))
(define (instrument-numeric-literals stx3 n)
(syntax-parse stx3
(num:number (datum->syntax #'num (+ (syntax->datum #'num) n)))
((first rest ...)
(with-syntax ((a (instrument-numeric-literals #'first n))
((b ...) (instrument-numeric-literals #'(rest ...) n)))
#'(a b ...)))
(x #'x)))
(syntax-parse stx
((_ params . body)
(let ((count (count-numeric-literals #'body)))
(with-syntax ((instrumented (instrument-numeric-literals #'body count)))
#'(lambda params . instrumented))))))
> (define-fun (fun) (+ 1 2 3 4))
> (fun)
26