16
votes

I am attempting to iterate over a vector of "lines" in Clojure. Essentially, it looks like:

[{:start {:x 1 :y 3 :z 4}, :end {:x 3 :y 7 :z 0}}, ...]

I would like to apply a function that prints each of these "lines" onto a new line, ala:

(map #(println %) vector-of-lines)

but that doesn't appear to call the function. Should I not be using the "map" function in this instance?

4
The hashmap bit is a red herring, and so I removed it from the title.missingfaktor

4 Answers

17
votes
(dorun (map println vector-of-lines))

dorun forces the evaluation of the lazy sequence, but also discards the individual results of each of item in the sequence. This is perfect for sequences that are purely for side-effects which is exactly what you want here.

16
votes

map is lazy and won't realize results unless you ask for them. If you want to perform a side effect for each element in a sequence, and don't care about the return value, use doseq:

;; returns nil, prints each line
(doseq [line vector-of-lines]
  (println line))

If you do care about the return value, use (doall):

;; returns a sequence of nils, prints each line
(doall (map println vector-of-lines))
4
votes

To add to Justin's answer, doseq is a macro, and thus carries with it all the limitations of macros.

I would write a foreach function that internally uses doseq.

user=> (defn foreach [f xs] (doseq [x xs] (f x)))
#'user/foreach

user=> (foreach println [11 690 3 45])
11
690
3
45
nil
0
votes

Since Clojure 1.7 there is run! which does what you want. The naming of this method may be related to the workaround with dorun and map. Be careful with using map for such occasions. Suppose that you make another call to map inside your function that you passed in. That will require walking the sequence as well. Thus, you will need to use dorun twice.