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

时间:2018-12-20 06:41:35

标签: racket

我正在尝试编写一个宏生成宏,其中生成的宏带有可变数量的参数。

我想知道是否有一种方法可以使以下代码起作用:

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

现在它说:“ pattern variablesellipsistemplate前没有...

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

2 个答案:

答案 0 :(得分:6)

至少有3种“样式”。

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

Soegaard already answered,您可以用...替换正文中的每个(... ...),以便将其解释为属于内部宏的文字省略号,而不是“元”属于外部宏的省略号:

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

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

缺点:如果您以前没看过(... ...),看起来会感到困惑

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

但是,(... <something>)周围的事物不仅限于...。如果您在其中放置整个模板,则该模板中的所有...都将被“引用”,以相同的方式视为文字而不是meta:

(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>)

您可以使用#: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和元...椭圆。在我看来,它看起来比(... ...)((... ...) (... ...))少混乱。

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

答案 1 :(得分:5)

...属于外部define-syntax-rule。为了 要在输出中产生省略号,您需要用(... ...)对其进行引用。

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

为了娱乐:如果您需要编写一个产生一个产生宏的宏的宏,则需要((... ...) (... ...))产生一个省略号。