Clojure: reduce vs. apply
For newbies looking at this answer,
be careful, they are not the same:
(apply hash-map [:a 5 :b 6])
;= {:a 5, :b 6}
(reduce hash-map [:a 5 :b 6])
;= {{{:a 5} :b} 6}
Opinions vary- In the greater Lisp world, reduce
is definitely considered more idiomatic. First, there is the variadic issues already discussed. Also, some Common Lisp compilers will actually fail when apply
is applied against very long lists because of how they handle argument lists.
Amongst Clojurists in my circle, though, using apply
in this case seems more common. I find it easier to grok and prefer it also.
It doesn't make a difference in this case, because + is a special case that can apply to any number of arguments. Reduce is a way to apply a function that expects a fixed number of arguments (2) to an arbitrarily long list of arguments.
reduce
and apply
are of course only equivalent (in terms of the ultimate result returned) for associative functions which need to see all their arguments in the variable-arity case. When they are result-wise equivalent, I'd say that apply
is always perfectly idiomatic, while reduce
is equivalent -- and might shave off a fraction of a blink of an eye -- in a lot of the common cases. What follows is my rationale for believing this.
+
is itself implemented in terms of reduce
for the variable-arity case (more than 2 arguments). Indeed, this seems like an immensely sensible "default" way to go for any variable-arity, associative function: reduce
has the potential to perform some optimisations to speed things up -- perhaps through something like internal-reduce
, a 1.2 novelty recently disabled in master, but hopefully to be reintroduced in the future -- which it would be silly to replicate in every function which might benefit from them in the vararg case. In such common cases, apply
will just add a little overhead. (Note it's nothing to be really worried about.)
On the other hand, a complex function might take advantage of some optimisation opportunities which aren't general enough to be built into reduce
; then apply
would let you take advantage of those while reduce
might actually slow you down. A good example of the latter scenario occuring in practice is provided by str
: it uses a StringBuilder
internally and will benefit significantly from the use of apply
rather than reduce
.
So, I'd say use apply
when in doubt; and if you happen to know that it's not buying you anything over reduce
(and that this is unlikely to change very soon), feel free to use reduce
to shave off that diminutive unnecessary overhead if you feel like it.