定义宏生成的宏,它接受可变数量的参数

JRR*_*JRR 4 racket

我正在尝试编写一个宏生成宏,它生成的宏采用可变数量的参数.

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

(define-syntax-rule (greet name)
  (define-syntax-rule (name args ...)
    (printf "hello ~a~n" (list args ...))))
Run Code Online (Sandbox Code Playgroud)

现在,它说:"没有pattern variables之前ellipsistemplate在:..."

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

Ale*_*uth 6

这样做至少有3种"样式".

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

Soegaard 已经回答说你可以替换...身体中的每一个(... ...),因此它被解释为属于内部宏的文字省略号而不是属于外部宏的"元"省略号:

(define-syntax-rule (greet name)
  (define-syntax-rule (name args (... ...))
    (printf "hello ~a~n" (list args (... ...)))))
Run Code Online (Sandbox Code Playgroud)

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

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

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

然而,放置(... <something>)一些东西并不仅限于此....如果你在那里放置一个完整的模板,那么...该模板中的任何一个也将被"引用",被视为文字而不是元,以同样的方式:

(define-syntax-rule (greet name)
  (...
   (define-syntax-rule (name args ...)
     (printf "hello ~a~n" (list args ...)))))
Run Code Online (Sandbox Code Playgroud)

优点:如果你有更大的嵌套深度,你可能不需要((... ...) (... ...))像选项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>)
Run Code Online (Sandbox Code Playgroud)

您可以使用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))))
Run Code Online (Sandbox Code Playgroud)

优点:灵活,您可以在体内自由混合字面ooo和元...椭圆.对我来说,它看起来不像是(... ...)或混淆((... ...) (... ...)).

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


soe*_*ard 5

...属于外define-syntax-rule.为了在输出中生成省略号,您需要引用它(... ...).

(define-syntax-rule (greet name)
  (define-syntax-rule (name args (... ...))
    (printf "hello ~a~n" (list args (... ...)))))
Run Code Online (Sandbox Code Playgroud)

为了好玩:如果您需要编写一个生成宏的宏来生成宏,则需要((... ...) (... ...))生成省略号.