关键字和默认参数宏干扰 Racket 中的变量参数

Keyword and default argument macro interfering with variable arguments in Racket

我正在使用本页 () 中提到的宏,它允许我使用 {arg_name arg_value} 作为默认参数和命名参数(不需要 #: key_name)。它在其他方面都可以正常工作,但它会干扰带有可变参数 (fnname .vars) 的函数声明。错误只是 "bad syntax"。如何纠正?感谢您的评论/回答。

编辑:我当前的代码是:

(require syntax/parse/define ; for define-simple-macro
         (only-in racket [define old-define] [#%app old-#%app])
         (for-syntax syntax/stx)) ; for stx-map

(begin-for-syntax
  ;; identifier->keyword : Identifer -> (Syntaxof Keyword)
  (define (identifier->keyword id)
    (datum->syntax id (string->keyword (symbol->string (syntax-e id))) id id))
  ;; for use in define
  (define-syntax-class arg-spec
    [pattern name:id
             ;; a sequence of one thing
             #:with (norm ...) #'(name)]
    [pattern {name:id default-val:expr}                 ; rn: ch if {} needed here; since works well with [] here; 
             #:when (equal? #\{ (syntax-property this-syntax 'paren-shape))
             #:with name-kw (identifier->keyword #'name)
             ;; a sequence of two things
             #:with (norm ...) #'(name-kw {name default-val})]))

(define-syntax-parser define         ; instead of define-simple-macro; 
  [(define x:id val:expr)
   #'(old-define x val)]
  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)])

(begin-for-syntax
  ;; for use in #%app
  (define-syntax-class arg
    [pattern arg:expr
             #:when (not (equal? #\{ (syntax-property this-syntax 'paren-shape)))
             ;; a sequence of one thing
             #:with (norm ...) #'(arg)]
    [pattern {name:id arg:expr}
             #:when (equal? #\{ (syntax-property this-syntax 'paren-shape))
             #:with name-kw (identifier->keyword #'name)
             ;; a sequence of two things
             #:with (norm ...) #'(name-kw arg)]))

(require (for-syntax (only-in racket [#%app app])))

(define-simple-macro (#%app fn arg:arg ...)
  #:fail-when (app equal? #\{ (app syntax-property this-syntax 'paren-shape))
  "function applications can't use `{`"
  (old-#%app fn arg.norm ... ...))

我不确定要更改哪一部分。如果我删除最后一部分(定义简单宏),{} 中的 named/default 参数将不起作用。

进一步编辑:我将代码修改如下:

(define-syntax-parser define         ; instead of define-simple-macro; 
  [(define x:id val:expr)
   #'(old-define x val)]
  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)]
  [(define (fn . vars) body ...+)
   #'(old-define (fn . vars) body ...)]      )

有效:

(define (testvars . vars)
  (println (list? vars))
  (for ((item vars))(println item))     )

(testvars 1 2 3)
#t
1
2
3

但为什么我还需要“(define-simple-macro ..”部分?另外,为什么我需要 2 个“(begin-for-syntax..”定义?

再次编辑:进一步修改:

(define-syntax-parser define         
  [(define x:id val:expr)
   #'(old-define x val)]
  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)]
  [(define (fn arg:arg-spec ... . vars) body ...+)                
   #'(old-define (fn arg.norm ... ... . vars) body ...)]
  )

以上最终适用于命名参数和变量参数,例如(fnname {x 0} {y 1} 10 20 30),感谢@AlexKnauth 在下方评论中提供的所有帮助。

正如我们在评论中发现的那样,您所要做的就是向 define 宏添加第三种情况,类似于第二种情况,但在 [= 之后添加 . rst 15=] 在模式中,并在模板中的 arg.norm ... ... 之后再次出现。

第二种情况是

  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)]

新案例类似,但增加了. rst

  [(define (fn arg:arg-spec ... . rst) body ...+)                
   #'(old-define (fn arg.norm ... ... . rst) body ...)]

在上下文中它看起来像这样。

(define-syntax-parser define         
  [(define x:id val:expr)
   #'(old-define x val)]
  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)]
  [(define (fn arg:arg-spec ... . rst) body ...+)                
   #'(old-define (fn arg.norm ... ... . rst) body ...)]
  )