Consider run!
Sometimes you need to perform a side effect for each element in a sequence. For the sake of argument, let's say we want to prn
each of the items in [0 1 2 3 4]
.
The existing core function doseq
can be used to accomplish this:
(doseq [x [0 1 2 3 4]]
(prn x))
Since doseq
is modeled after for
, lots of sophisticated things can be done using its mini-language, with :let
, :while
, and :when
.
But, for applying prn
to each of the elements, you may be tempted to reach for this simpler looking map
form:
(map prn [0 1 2 3 4])
While this has appeal, it is laced with subtle issues surrounding evaluation and lazy sequences.
When you have something like this, you don't need to resort to dorun
to force evaluation. Instead, simply replace map
with run!
, directly indicating your intent:
(run! prn [0 1 2 3 4])
As its docstring indicates, run!
is based on reduce
, which is eager, thus side-stepping any issues with lazy sequences. Also with run!
, no temporary sequence is produced and discarded as would be with (dorun (map ...))
.
And, since it is based on reduce
, this gives you a way to terminate processing early—you can use reduced
:
(run! (fn [n]
(if (< n 3)
(prn n)
(reduced nil)))
(range))
This will apply prn
to only the first 3 elements of the infinite sequence returned by (range)
and terminate:
0
1
2
Note that, while the intent of
run!
is that it be used solely for side effects (and thus is without a meaningful return value), it can return non-nil
in its initially-released form in Clojure and ClojureScript.
The run!
function was introduced with the work done to add transducers to Clojure 1.7, also first appearing in ClojureScript 0.0-2301.