I want to create a function that takes in a required argument x, and either a optional argument opt1 OR a keyword argument opt2.
Right now I have
(defn foo x & [opt1 {:keys [opt2]}]
...
But the above signature only lets me pass in keyword argument opt2 when both x and opt1 is present like
(foo 'x 'opt1 {:opt2 'opt2})
not like this
(foo 'x {:opt2 'opt2})
Please help me create a function that takes a required argument X and either opt1 or opt2, where opt2 is a keyword argument.
Thank you.
EDIT: I want to do the same for other macros as well. So I still need to use the defmacro.
The problem is ambiguity. Consider a function (fn foo [x y & args])
that takes two optional arguments and then any number of keyword arguments. If you then call it like (foo :bar :baz)
, how does your program handle it? x
=> :bar
, y
=> :baz
? Or x
and y
not provided, with a single :bar
=> :baz
keyword argument?
Even in Common Lisp, which has arguably even more flexibility than Clojure in parsing function parameters, mixing optional and keyword arguments is not recommended, according to at least one popular book.
Your best bet is to change all of your arguments to positional arguments, or all of your parameters to keyword arguments. If you use keyword arguments, you can use hash-map destructuring to provide defaults for "optional" keyword parameters.
user> (defn foo [& {:keys [x y bar]
:or {x 1 y 2 bar 3}}]
(prn [x y bar]))
#'user/foo
user> (foo)
[1 2 3]
nil
user> (foo :bar :baz)
[1 2 :baz]
nil
you have to check if the aditional arguments are keyword arguments or not anyway (I assume your or is an exclusive or) so you can do it like this:
(defn foo [& args]
(if (= (count args) 1)
(let [[opt1] args] (println opt1))
(let [{:keys [opt2]} args] (println opt2))))
check the arguments if they are keyword arguments or not. As you only have one optional parameter it's easy: check if there's only one as keyword arguments require two.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With