Reputation: 13383
Is there a way to specify keyword arguments to a function as a dictionary, analogously to the .
that allows us to supply a list for positional arguments? I'm looking for something analogous to python's *args and **kwargs.
In more detail:
If we want to handle an arbitrary number of positional arguments in a function, we can define it like so:
(define (my-add . args)
(apply + args))
and use it with a variable number of arguments as:
(define numbers '(1 2 3))
(apply my-add numbers) ;=> 6
(define numbers '(1 2 3 4 5))
(apply my-add numbers) ;=> 15
Even for functions that don't explicitly handle the "rest" of the positional arguments via the .
syntax, we can use apply
to unpack positional arguments from a list.
(apply expt '(2 3)) ;=> 8
I see that apply
does forward on keyword arguments in addition to positional arguments. However, this only works if the invoked function itself identifies the specific keyword arguments it is expecting. For instance, in a dispatch situation where the function doesn't itself use the keyword arguments but merely intends to forward them on to some appropriate handler, using apply in this way doesn't do what we need because the function would need to know about all the keyword arguments accepted by any function it is dispatching to, not to mention do the legwork of repacking them in some way before invoking the handlers.
As a tangible example illustrating the problem, consider a simple "echo args" function that echoes all of the arguments passed to it:
(define (echo-args . args)
(printf "~a" args))
With only positional args:
> (echo-args 1 2 5)
(1 2 5)
With keyword args:
> (echo-args 1 2 5 #:key 'hi)
; application: procedure does not accept keyword arguments
; procedure: echo-args
; arguments...:
; 1
; 2
; 5
; #:key 'hi
; Context:
; /Applications/Racket v7.5/collects/racket/repl.rkt:11:26
Is there a built-in way to accomplish this kind of thing? If not, any ideas on how to make this work?
Upvotes: 1
Views: 789
Reputation: 22332
What you are looking for is make-keyword-procedure
. This generates a procedure that accepts all keyword arguments, and can be accessed from a dictionary.Taking the example from the docs:
> (define show
(make-keyword-procedure (lambda (kws kw-args . rest)
(list kws kw-args rest))))
> (show #:blue 3 4)
'((#:blue) (3) (4))
Of course, a dictionary implemented as two lists can be a bit annoying. So Alex Knauth made a small package hash-lambda which gives you a more direct hash-map like API.
Upvotes: 5