通过嵌套宏中的省略号捕获可变数量的参数;缺少模式变量错误

Sam*_*Sam 5 macros racket

考虑两个宏的情况:outer-macro定义一些实体的一般结构,并inner-macro扩展外部宏的范围。以下代码捕获了我的意图,其中预期的输出是打印语句。本示例对内部宏的模式抛出以下错误:(_ value ...)

syntax: no pattern variables before ellipsis in template in: ...
Run Code Online (Sandbox Code Playgroud)

我打算以与外部宏value ...body ...模式相同的方式使用。实际上,“值”列表正是我所需要的(不一定是非常灵活的“省略号模式”)。遗憾的是,这种方式无法正常工作。如何捕获内部宏中可变数量的参数?

#lang racket

(require
  racket/stxparam
  (for-syntax syntax/parse))

(define-syntax-parameter inner-macro
  (lambda (stx)
    (raise-syntax-error 'inner-macro "generic error message" stx)))

(define-syntax (outter-macro stx)
  (syntax-parse stx
    [(_ body:expr ...+)
     #'(syntax-parameterize
        ([inner-macro
          (lambda (stx)
            (syntax-case stx ()
              [(_ value ...)
               (printf "values are: ~a~n" (list value ...))]))])
        body ...)]))

(outter-macro
 (inner-macro 'a 'b 'c))

; expected result
; > "values are: (a b c)"
Run Code Online (Sandbox Code Playgroud)

Ale*_*uth 7

亚历克西斯·金的答案很好。但是,我认为更简单的另一种实现方法是使用#:with模式(或with-syntax)来定义类似ooo文字省略号的内容。

您可以使用来创建文字省略号quote-syntax,因此#:with子句看起来像#:with ooo (quote-syntax ...)。然后,ooo无论何时要在宏的输出中生成省略号,都可以使用。

(define-syntax (outer-macro stx)
  (syntax-parse stx
    [(_ body:expr ...+)
     #:with ooo (quote-syntax ...)
     #'(syntax-parameterize
        ([inner-macro
          (lambda (stx)
            (syntax-case stx ()
              [(_ value ooo)
               #'(printf "values are: ~a~n" (list value ooo))]))])
    body ...)]))
Run Code Online (Sandbox Code Playgroud)

  • 这个问题有3种不同的风格:[定义接受可变数量参数的宏生成的宏](/sf/ask/3770453431/ generated-macros-that-take-参数数量不变) (2认同)

Ale*_*ing 5

要“逃避”语法模板中的省略号,可以使用语法(... <form>),其中<form>语法模板是...按字面意义对待的语法模板。因此,您可以包装一段语法以包括文字省略号:

> #'(... (syntax-rules ()
           [(x ...) (list x ...)]))
#<syntax:4:9 (syntax-rules () ((x ...) (li...>
Run Code Online (Sandbox Code Playgroud)

您可以使用它来包围内部宏定义以转义内部椭圆:

(define-syntax (outer-macro stx)
  (syntax-parse stx
    [(_ body:expr ...+)
     #'(syntax-parameterize
        ([inner-macro
          (lambda (stx)
            (... (syntax-case stx ()
                   [(_ value ...)
                    (printf "values are: ~a~n" (list value ...))])))])
        body ...)]))
Run Code Online (Sandbox Code Playgroud)

但是,这实际上并不完全正确,因为您的syntax-case身体是错误的,它不会返回语法对象。您只是#'(printf ...)(或可以使用syntax-rules)之前缺少,所以正确的实现应为以下内容:

(define-syntax (outer-macro stx)
  (syntax-parse stx
    [(_ body:expr ...+)
     #'(syntax-parameterize
        ([inner-macro
          (lambda (stx)
            (... (syntax-case stx ()
                   [(_ value ...)
                    #'(printf "values are: ~a~n" (list value ...))])))])
        body ...)]))
Run Code Online (Sandbox Code Playgroud)

这应该按预期工作。