首页 > 解决方案 > 定义接受可变数量参数的宏生成的宏

问题描述

我正在尝试编写一个宏生成宏,它生成的宏需要可变数量的参数。

我想知道是否有办法使以下代码工作:

(define-syntax-rule (greet name)
  (define-syntax-rule (name args ...)
    (printf "hello ~a~n" (list args ...))))

现在它说“pattern variables之前ellipsis在里面没有template...

如果我自己采用内部define-syntax-rule,它可以正常工作,那么为什么当它由另一个宏生成时它不工作呢?

标签: racket

解决方案


这样做至少有 3 种“风格”。

1:省略号——分别引用每个省略号

Soegaard已经回答说,您可以将...正文中的every 替换为(... ...),以便将其解释为属于内部宏的文字省略号,而不是属于外部宏的“元”省略号:

(define-syntax-rule (greet name)
  (define-syntax-rule (name args (... ...))
    (printf "hello ~a~n" (list args (... ...)))))

优点:灵活,可以在体内自由混合文字(... ...)和元椭圆...

缺点:如果你以前没见过,看起来很(... ...)混乱

2:省略号-引用整个内部宏定义

但是,放置(... <something>)某些东西不仅限于.... 如果您将整个模板放在那里,则...该模板中的任何 s 也将被“引用”,被视为文字而不是元,以相同的方式:

(define-syntax-rule (greet name)
  (...
   (define-syntax-rule (name args ...)
     (printf "hello ~a~n" (list args ...)))))

优点:如果您有更大的嵌套深度,则不需要((... ...) (... ...))像选项 1 那样,您只需要(... <something-containing (... <something>)>)

缺点:僵化,如果你把(... <something>)一些东西放在周围,你就不能在那个东西里面使用元省略号。您不能像使用样式 1 或 3 那样自由地混合文字和元省略号。

3:创建一个模式变量来表示文字省略号

这是另一种方式,我觉得不太容易混淆,但它需要使用define-simple-macro而不是define-syntax-rule,以便您可以使用 绑定新的模式变量#:with

(require syntax/parse/define)

(define-simple-macro (<name> <arguments>)
  #:with <pattern-variable> <expression>
  <body-expression>)

您可以使用 with#:withooo模式变量绑定到文字省略号:#:with ooo (quote-syntax ...)

(require syntax/parse/define)

(define-simple-macro (greet name)
  #:with ooo (quote-syntax ...)
  (define-syntax-rule (name args ooo)
    (printf "hello ~a~n" (list args ooo))))

优点:灵活,您可以在正文中自由混合文字ooo和元椭圆。...对我来说,它看起来不像(... ...)or那样令人困惑((... ...) (... ...))

缺点:对于更深的嵌套,您可能需要多个#:with- 定义,每个元级别一个。


推荐阅读