brundolf
brundolf

Reputation: 1490

How to combine explicit args with variable args in function call

In JavaScript, one can do the following:

function foo(arg1, arg2, arg3) {
  ...
}

var others = [ 'two', 'three' ];
foo('one', ...others);  // same as foo('one', 'two', 'three')

In Clojure, "variable args" can be accepted like so:

(defn foo [arg1 & others]
  ...)

But to pass them in combination with other args, you have to do this:

(apply foo (concat '("one") others))

Which is frankly really ugly. It's also impossible when what you need to do is recur:

(apply recur (concat '("one") others)) ;; doesn't work

Is there a better way to do this? And if not, is there any way at all to accomplish it in the recur case?

Upvotes: 1

Views: 428

Answers (1)

Taylor Wood
Taylor Wood

Reputation: 16194

But to pass them in combination with other args, you have to do this: (apply foo (concat '("one") others))

You don't have to do that: apply is also a variadic function that can take arguments before the final sequence argument e.g.

(apply foo "one" others)

You can pass any number of individual arguments before the final sequence argument to apply.

user=> (defn foo [arg1 & args] (apply println arg1 args))
#'user/foo
user=> (apply foo "one" 2 "three" [4 "five" 6.0])
one 2 three 4 five 6.0

To further demonstrate, these calls to + are functionally equivalent:

(apply + 1 2 [3])
(apply + 1 [2 3])
(apply + [1 2 3])

It's also impossible when what you need to do is recur

recur is a special form, and apply doesn't work with it like it would a typical Clojure function.

is there any way at all to accomplish it in the recur case?

Not with apply. You can recur with variadic args, but you can't (apply recur ...).

Upvotes: 5

Related Questions