When you say that you are running
(integers 10)
what you're really doing is something like this:
user> (integers 10)
In other words, you're evaluating that form in a REPL (read-eval-print-loop).
The "read" step will convert from the string "(integers 10)"
to the list (integers 10)
. Pretty straightforward.
The "eval" step will look up integers
in the surrounding context, see that it is bound to a function, and evaluate that function with the parameter 10
:
(cons 10 (lazy-seq (integers (inc 10))))
Since a lazy-seq
isn't realized until it needs to be, simply evaluating this form will result in a clojure.lang.Cons
object whose first
element is 10
and whose rest
element is a clojure.lang.LazySeq
that hasn't been realized yet.
You can verify this with a simple def
(no infinite hang):
user> (def my-integers (integers 10))
;=> #'user/my-integers
In the final "print" step, Clojure basically tries to convert the result of the form it just evaluated to a string, then print that string to the console. For a finite sequence, this is easy. It just keeps taking items from the sequence until there aren't any left, converts each item to a string, separates them by spaces, sticks some parentheses on the ends, and voilĂ :
user> (take 5 (integers 10))
;=> (10 11 12 13 14)
But as you've defined integers
, there won't be a point at which there are no items left (well, at least until you get an integer overflow, but that could be remedied by using inc'
instead of just inc
). So Clojure is able to read and evaluate your input just fine, but it simply cannot print all the items of an infinite result.