I've tried to improve on Andy's answer, but he pretty much nailed it. The first solution is creating a pyramid of streams -- each call to fib
creates another fibonacci stream, and each of these new streams will create new stream themselves, and so on.
To be clear, there are three streams resulting from a call to fib
:
- One created by
fib
in fib zip fib.tail
- One created by
fib.tail
in fib zip fib.tail
- One created by
map
(remember, map
creates a new collection)
Since the first two are calls to fib
, they'll create three streams each, and so on.
Here's a rough "picture" of it:
1
1
1 2 1
1 3 1 2 1
1 2 1 5 1 3 1 2 1
1 3 1 2 1 8 1 2 1 5 1 3 1 2 1
And this goes on and on. The middle stream is computed using the highest streams to its left and right (fib and fib.tail). Each of them is computed using lower streams on their left and right. Each of these lower streams is computed using streams shown on the last line.
We could continue this on and on, but you can see that, by the time we computed 8, we already have 14 other fibonacci streams going on.
If you change it from def
to val
, all these new streams disappear, because fib
and fib.tail
will refer to an existing stream instead of creating new streams. And since no new stream will be created, there will be no further calls to fib
and fib.tail
.
Now, if you look at the second answer, you'll notice that there is a single fib
call, and no map
or similar method, so there's no multiplication effect.