When I run (println (iterate inc 0))
in my repl, I will get something like this:
user=> (println (iterate inc 0))
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 ....................
My expectation when I run the code is that repl shows nothing and just stuck because (iterate inc 0)
never ends. But, I see (0 1 2 3 ...
.
(iterate inc 0)
generates infinite sequence which never returns. If it never ends, then why println
starts printing values?
In other words, why (println xx)
is started being evaluated even if the input is never finished being evaluated?
You should read up on lazy seqs in Clojure. They're able to produce values that can be consumed incrementally before the whole sequence is realized (which, in this case, will never happen).
It might help to think of it as push vs pull. Instead of iterate creating an entire list of values and then pushing them to the println function (which would never happen), iterate just hands it a lazy sequence, and println pulls values as it needs them. This is why (take 5 (iterate inc 0)) works; take only tries to pull 5 values before stopping.
Clojure's printing is smarter than System.out.println
; it can be customized for different types. In the case of sequences, it walks through element-by-element, printing each one as it goes - we don't have to wait until the entire sequence is evaluated to start printing things.
By contrast, System.out.println
, which calls toString
before printing, behaves more like you might expect. It hangs forever, not printing anything because toString
needs to evaluate the entire sequence - or, at least, it would hang forever if it didn't run out of memory trying to build the string.
That said, the entire expression is indeed stuck - if you were waiting for it to stop printing, you'd wait forever:
(do
(println (iterate inc 0))
(println "Never reached!"))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With