How to make a Clojure function take a variable number of parameters?
Solution 1
In general, non-commutative case you can use apply:
(defn sum [& args] (apply + args))
Since addition is commutative, something like this should work too:
(defn sum [& args] (reduce + args))
&
causes args
to be bound to the remainder of the argument list (in this case the whole list, as there's nothing to the left of &
).
Obviously defining sum like that doesn't make sense, since instead of:
(sum a b c d e ...)
you can just write:
(+ a b c d e ....)
Solution 2
Yehoanathan mentions arity overloading but does not provide a direct example. Here's what he's talking about:
(defn special-sum
([] (+ 10 10))
([x] (+ 10 x))
([x y] (+ x y)))
(special-sum)
=> 20
(special-sum 50)
=> 60
(special-sum 50 25)
=> 75
Solution 3
(defn my-sum
([] 0) ; no parameter
([x] x) ; one parameter
([x y] (+ x y)) ; two parameters
([x y & more] ; more than two parameters
(reduce + (my-sum x y) more))
)
Solution 4
defn
is a macro that makes defining functions a little simpler. Clojure supports arity overloading in a single function object, self-reference, and variable-arity functions using&
From http://clojure.org/functional_programming
Solution 5
(defn sum [& args]
(print "sum of" args ":" (apply + args)))
This takes any number of arguments and add them up.
Related videos on Youtube
rodrigoalvesvieira
I am a software engineer who writes mostly Ruby, Go and C++.
Updated on July 08, 2022Comments
-
rodrigoalvesvieira almost 2 years
I'm learning Clojure and I'm trying to define a function that take a variable number of parameters (a variadic function) and sum them up (yep, just like the + procedure). However, I don´t know how to implement such function
Everything I can do is:
(defn sum [n1, n2] (+ n1 n2))
Of course this function takes two parameteres and two parameters only. Please teach me how to make it accept (and process) an undefined number of parameters.
-
rodrigoalvesvieira about 12 yearsYes, doesn´t make sence, but it is a good illustration to your answer. Thanks.
-
avichalp almost 8 years@soulcheck: is there a way to pass a
seq
to your sum function. For example : (sum '(1 2 3)) and the result is 6 ? -
soulcheck almost 8 years@avichalp that would be another function. just remove
&
from either version -
avichalp almost 8 years@soulcheck: No. I mean using the same function signature. I am a newbie in clojure hence I am able to put my point clearly here. What I would like to know is in python I can use *args and if a function is defined such that it takes *args (eg
def fn(*args): pass
) I can call it by giving a list like fn(*list_of_args). Can I do the same thing in clojure ? -
soulcheck almost 8 years@avichalp the call to
def fn(*args): pass
wouldn't befn([1,2,3])
butfn(1,2,3)
(obviously depending what you want to do exactly, but I'm trying to follow the spirit here) -
avichalp almost 8 years@soulcheck: In python I can pass a list with an star prepended to it like
fn(*[1, 2, 3])
it will be equivalent tofn(1, 2, 3)
. Is this possible in clojure ? -
fingaz over 7 years@avichalp the & creates a seq out of the arguments passed to the function. If you were to pass a seq, you would be passing a seq of seqs and apply would not be able to evaluate the seq because it expects a clojure.lang.Number type based on the arguments asked for by +
-
nha almost 7 yearsDuplicate of @soulcheck answer stackoverflow.com/a/9242671/1327651
-
Erik Kaplun over 5 yearsAlso works with lambdas:
(fn ([] (+ 10 10)) ([x] (+ 10 x)) ([x y] (+ x y)))
-
Yarin almost 3 yearsWhat @avichalp is asking about is Python's star operator, which unpacks a list argument into individual arguments in a function call. The answer is no, Clojure doesn't have that, you would use
apply
instead. See stackoverflow.com/a/10802391/165673.