Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(println (iterate inc 0)): why does this even start printing?

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?

like image 564
kimh Avatar asked May 17 '15 09:05

kimh


2 Answers

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.

like image 136
Anthony R. Avatar answered Nov 15 '22 07:11

Anthony R.


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!"))
like image 27
Beyamor Avatar answered Nov 15 '22 08:11

Beyamor