Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the execution of a lazy fibonacci implementation in Clojure

I'm trying to understand the execution of the following code:

(def fibs 
  (concat (lazy-seq [0 1]) (lazy-seq (map + fibs (rest fibs)))))

This is what I would expect the execution to look like

[0 1 : (map + [0 1] [1]) => 1
[0 1 1 : (map + [0 1 1] [1 1]) => 1 2
[0 1 1 1 2 : (map + [0 1 1 2] [1 1 2]) => 1 2 3
[0 1 1 1 2 1 2 3 : (map + [0 1 1 2 3] [1 1 2 3]) => 1 2 3 5
[0 1 1 1 2 1 2 3 1 2 3 5 .... 

Which is obviously incorrect, since the result is wrong. The only execution I could come up with that produced the correct result is this:

[0 1 : (map + [0 1] [1]) => 1
[0 1 1 : (map + [1 1] [1]) => 2
[0 1 1 2 : (map + [1 2] [2]) => 3
[0 1 1 2 3 : (map + [2 3] [3]) => 5
[0 1 1 2 3 5 ....

Is this a correct "representation" of the state of head and tail during the execution? If so, why does (rest fibs) return a single item? Is it because of a recursive call like (rest (rest (rest [1 1 2 3])))?

like image 246
ebaxt Avatar asked Nov 16 '12 21:11

ebaxt


People also ask

What is a lazy sequence in Clojure?

However, Clojure supports lazily evaluated sequences. This means that sequence elements are not available ahead of time and produced as the result of a computation. The computation is performed as needed. Evaluation of lazy sequences is known as realization.

What is lazy sequence?

A sequence containing the same elements as a Base sequence, but on which some operations such as map and filter are implemented lazily.


1 Answers

Fibs is (0 1 ...) (because of the (concat [0 1] ... ) at the beginning). (rest fibs) is (1 ...). Then (map + fibs (rest fibs)) is

((+ 0 1) ...) => (1 ...)

So fibs is (0 1 1 ...). Since we got the next item, we can calculate yet another one:

(1 (+ 1 1) ...) => (1 2 ...)

And it goes on...

(1 2 (+ 1 2) ...)

Think of fibs as if it was already there, and the state of (map + fibs (rest fibs) as moving on the list of the fibs that already exist (that's fine because it ends up calculating everything we need on the way).

It could also help to just write down the two sequences:

 (0 1 1 2 3 5 ...)
+(1 1 2 3 5 ...)
=(1 2 3 5 8 ...)

(I'd draw arrows here to indicate what we already got and where the result goes, but I can't do that here so well).

like image 183
Cubic Avatar answered Sep 28 '22 07:09

Cubic