I am using the macro mentioned on this page (Macro for keyword and default values of function arguments in Racket) which permits me to use {arg_name arg_value} for default and named arguments (without the need for #:key_name). It is otherwise working all right but it is interfering with declaration of functions with variable arguments (fnname . vars). The error is simply "bad syntax". How can this be corrected? Thanks for your comments / answers.
Edit: My current code is:
(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 ... ...))
I am not sure which part to change. If I remove last part (define-simple-macro) the named/default arguments in {} do not work.
Further Edit: I have modified the code as follows:
(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 ...)] )
and it works:
(define (testvars . vars)
(println (list? vars))
(for ((item vars))(println item)) )
(testvars 1 2 3)
#t
1
2
3
But why do I still need "(define-simple-macro .." part? Also, why do I need 2 "(begin-for-syntax.." definitions?
Edit again: further modification:
(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 ...)]
)
Above finally works with both named and variable arguments, e.g. (fnname {x 0} {y 1} 10 20 30), thanks to all the help from @AlexKnauth in comments below.
definemacro in that question/answer doesn't support declaring "rest" arguments. When I was writing it, I didn't want to clutter the implementation with features that weren't really relevant. - Alex Knauthdefine-simple-macro, you'd have to usedefine-syntax-parser, with two cases, one for when there's no rest argument, and one where there is. - Alex Knauthdefineone is the one you need to change, and that's already written withdefine-syntax-parser. I had forgotten, but that makes this easier. You just have to add another case to the existingdefinemacro. - Alex Knauthdefine-simple-macrodefines the#%appmacro, which re-defines what function application looks like. If you leave that out, you will be able to call(greet #:hello "hi"), but not(greet [hello "hi"]). - Alex Knauthdefinemacro as an answer, although should should make surevarsis an identifier by writingvars:id, and you should make sure you can have some normal arguments followed by ` . rst-id` too - Alex Knauth