Sunday, December 8, 2013

Using lazy-seq

the documentation of lazy-seq says:

(lazy-seq & body)
Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?

To illustrate in an example below to calculate the Fibonacci series. We utilize this lazy-seq function.

(defn fibs2_sq [a b] (cons a (lazy-seq (fibs2_impl b (+ a b)))))
(fibs2_sq 0 1)

The output is something like (assuming you run (set! *print-length* 10) to limit the length of values being printed):
(0 1 1 2 3 5 8 13 21 34 55 89 ...)

This look normal, but what if we remove the invocation of lazy-seq function, and run below code:

(defn fibs_sq [a b] (cons a (fibs_sq b (+ a b))))
(take 10 (fibs_sq 0 1))

You will first hit an error saying:
ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow (Numbers.java:1388)

After change the second expression to
(take 10 (fibs_sq 0N 1N))

You still hit below error:
StackOverflowError   java.math.BigInteger.add (BigInteger.java:1048)

The implication is that lazy-seq only runs the code it wraps when needed. Otherwise, you run into an infinite loop, trying to produce an infinite sequence.

No comments:

Post a Comment