Reputation: 2050
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
?
Upvotes: 1
Views: 558
Reputation: 4901
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 ...)
.
Upvotes: 4
Reputation: 29958
Your existing solution isn't so bad. One small improvement is to use the into
function, which uses conj
internally to join two sequences together:
(defn my-update [what & items]
(update what :a into items))
with result
(my-update {:a [1]} 2 3 4) => {:a [1 2 3 4]}
Another alternative is to extract out the anonymous function into a named function:
(defn append-to-seq
[seq item items]
(-> (vec seq) ; ensure it is a vector so conj adds to the end, not beginning
(conj item)
(into items)))
(defn my-update [what item & items]
(update what :a append-to-seq item items))
Upvotes: 1