Search code examples
clojure

for doesn't produce output when there is also loop/recur in the same function body


Consider this code snippet:

(defn foo []
  (let [line (apply str (repeat 2 \.))
        lines (into [] (repeat 2 line))]
    (for [x lines] (println x)) ; this doesn't print
    (loop [remaining [[1 2] [3 4]]]
      (if (empty? remaining)
        (for [y lines] (println y)) ; but this does print
        (recur (rest remaining))))))

The output of running foo is:

..
..
(nil nil)

Thus, the line commented with this doesn't print produces no output. In fact, I can remove that line and get the same output.

The output I expected to get is:

..
..
..
..
(nil nil)

When I remove the whole loop/recur business, the line works as expected:

(defn foo []
  (let [line (apply str (repeat 2 \.))
        lines (into [] (repeat 2 line))]
    (for [x lines] (println x)))) ; now it prints

yields

..
..
(nil nil)

as expected. Why does the loop/recur prevent the for/println from generating output?


Solution

  • for is lazy. If nothing uses its result, nothing in its body will run.

    For the particular case of printing all the lines, you can simply print the whole collection - (println lines).

    Or, if you want each item to go onto its own line, (run! println lines).