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])))?
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.
A sequence containing the same elements as a Base sequence, but on which some operations such as map and filter are implemented lazily.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With