For kicks, I decided to write my own version of map
, but finally learn how to use lazy-seq
correctly and use it to make the map lazy:
(defn my-map [f [head & tail]]
(lazy-seq
(if head
(cons (f head) (my-map f tail))
tail)))
It works, but when I tested its lazy behavior against map
, I noticed something different. I'm using a helper-map function that prints when an element is processed:
(defn print-map [description-str f coll mapping-f]
(mapping-f
(fn [x]
(do
(print (str description-str ":" x))
(f x)))
coll))
When I use the standard map
function, the elements are processed one at a time, alternating between functions:
(defn -main []
(let [m map
coll (into '() (range 10 0 -1))
coll2 (print-map "A" identity coll m)
coll3 (print-map "B" identity coll2 m)]
(println (doall coll3))))
Prints:
A:1 B:1 A:2 B:2 A:3 B:3 A:4 B:4 A:5 B:5 A:6 B:6 A:7 B:7 A:8 B:8 A:9 B:9 A:10 B:10 (1 2 3 4 5 6 7 8 9 10)
Note how each number is processed by both functions first before the rest of the elements are seen by either function.
But when I change m
in -main
to my-map
, the processing order changes slightly:
A:1 A:2 B:1 A:3 B:2 A:4 B:3 A:5 B:4 A:6 B:5 A:7 B:6 A:8 B:7 A:9 B:8 A:10 B:9 B:10 (1 2 3 4 5 6 7 8 9 10)
Now the first function is run twice to start, the second function runs twice in a row in the end, and as a consequence, the mappings are no longer "in sync".
What's wrong with my-map
that causes this to happen?