我正在使用此页面上提到的宏(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在下面评论中提供的所有帮助。
答案 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 ...)]
)