I want to write a function which simply updates a vector in a map with new value, but can take any number of args, but at least one.
Here is example:
(defn my-update [what item & items]
(update what :desired-key conj item items))
Unfortunately, this doesn't work. Despite that update
do have a signature with multiple values (like [m k f x y]
), all remaining arguments to my-update
will be joined into one sequence, which will be passed to conj
as one argument.
Instead, wrapping conj
with apply
in an anonymous function does work, but looks not so elegant:
(defn my-update [what item & items]
(update what :desired-key #(apply conj % item items))
What is the idiomatic way of writing such a function like my-update
?
You can simply insert apply before update
. That will call the function update
with the arguments that follows except for the last argument which should be a sequence, whose elements become the remaining arguments in the call:
(defn my-update [what item & items]
(apply update what :desired-key conj item items))
(my-update {:desired-key [0]} 1 2 3 4)
;; => {:desired-key [0 1 2 3 4]}
(my-update {:desired-key [0]})
;; Exception: Wrong number of args (1) passed to: my-update
This way, you can keep the function argument list [what item & items]
that makes it clear that at least one item needs to be provided.
In general, a call (apply f a b c ... [x y z ...])
will evaluate to the same as (f a b c ... x y z ...)
.