1

I am wondering that lazy-seq returns a finite list or infinite list. There is an example,

(defn integers [n]
    (cons n (lazy-seq (integers (inc n)))))

when I run like

(first integers 10)

or

(take 5 (integers 10))

the results are 10 and (10 11 12 13 14) . However, when I run

(integers 10)

the process cannot print anything and cannot continue. Is there anyone who can tell me why and the usage of laza-seq. Thank you so much!

Xiufen Xu
  • 531
  • 1
  • 3
  • 19

4 Answers4

8

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.

amalloy
  • 89,153
  • 8
  • 140
  • 205
Sam Estep
  • 12,974
  • 2
  • 37
  • 75
0

When you try to print an unbounded lazy sequence, it will be completely realized, unless you limit *print-length*.

Svante
  • 50,694
  • 11
  • 78
  • 122
0

The lazy-seq macro never constructs a list, finite or infinite. It constructs a clojure.lang.LazySeq object. This is a nominal sequence that wraps a function of no arguments (commonly called a thunk) that evaluates to the actual sequence when called; but it isn't called until it has to be, and that's the purpose of the mechanism: to delay evaluating the actual sequence.

So you can pass endless sequences around as evaluated LazySeq objects, provided you never realise them. Your evaluation at the REPL invokes realisation, an endless process.

Thumbnail
  • 13,293
  • 2
  • 29
  • 37
-1

It's not returning anything because your integers function creates an infinite loop.

(defn integers [n]
  (do (prn n)
      (cons n (lazy-seq (integers (inc n))))))

Call it with (integers 10) and you'll see it counting forever.

jmargolisvt
  • 5,722
  • 4
  • 29
  • 46