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

时间:2016-08-09 15:25:20

标签: macros scheme racket

我正在使用此页面上提到的宏(Macro for keyword and default values of function arguments in Racket),它允许我使用{arg_name arg_value}作为默认和命名参数(不需要#:key_name)。它可以正常工作,但它干扰了带有可变参数的函数声明(fnname.vars)。错误只是“语法错误”。如何纠正?感谢您的意见/解答。

编辑:我当前的代码是:

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

我不确定要改变哪一部分。如果我删除最后一个部分(define-simple-macro),{}中的命名/默认参数不起作用。

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

(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“(开始为语法..”定义?

再次编辑:进一步修改:

(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在下面评论中提供的所有帮助。

1 个答案:

答案 0 :(得分:1)

正如我们在评论中指出的那样,您所要做的就是向define宏添加第三个案例,类似于第二个案例,但在. rst之后使用arg:arg-spec ...在模式中,再次在模板中的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 ...)]
  )