Macros 如何使用模板宏重写此宏?

Macros 如何使用模板宏重写此宏?,macros,scheme,racket,Macros,Scheme,Racket,假设我想在Racket/Scheme中定义一个宏,该宏由instruments“定义”。具体地说,它计算define主体中的文本数,然后将该数字添加到所有这些文本中(这应该发生在宏扩展阶段) 以下是以普通函数样式定义的宏(以列表形式在语法树上操作): 我想用普通的Racket/Scheme模板宏样式重写它。以下是我的(不成功)尝试: 其思想是分阶段插入代码:首先标记语法树中的所有节点,然后计算文本,在需要时用“transform”宏替换标记。。。正如注释的“displays”所示,宏“mark”

假设我想在Racket/Scheme中定义一个宏,该宏由instruments“定义”。具体地说,它计算define主体中的文本数,然后将该数字添加到所有这些文本中(这应该发生在宏扩展阶段)

以下是以普通函数样式定义的宏(以列表形式在语法树上操作):

我想用普通的Racket/Scheme模板宏样式重写它。以下是我的(不成功)尝试:

其思想是分阶段插入代码:首先标记语法树中的所有节点,然后计算文本,在需要时用“transform”宏替换标记。。。正如注释的“displays”所示,宏“mark”在所有“descent”完成之前开始扩展(因此它们仍然处于宏代码捕获的状态)。即使“display-counted-n”扩展得太快,而“n”仍然是0

有没有办法改变宏扩展的顺序?我希望Racket/Scheme分阶段进行扩展:首先是“下降”,然后是“标记”,然后是“变换”,然后是“显示-计数-n”


我已经阅读了的答案-似乎用模板宏实现这一任务的唯一方法是使用“秘密文本”,并在一个大宏定义中定义所有内容。然而,我想这会使代码更难编写和阅读。也许还有其他方法吗?

这是我的
语法案例版本
宏版本:

(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