Reputation: 601
There are a dozen of confusion when I use lazySeq.
Question:
(def fib
(lazy-seq
(concat [0 1] (map + fib (rest fib))))) ;; It's Ok
(take 10 fib) ;; Bomb
Got the error message: StackOverflowError clojure.lang.RT.more (RT.java:589)
And the following solutions works well:
(def fib
(concat [0 1] (lazy-seq (map + fib (rest fib))))) ;; Works well
(def fib
(lazy-cat [0 1] (map + fib (rest fib)))) ;; Works well
Both concat
and map
return lazy sequence, why the above programs look like each other but distinguish?
More detailedly, Why the first example (lazy-seq
wrapping the concat
) fail but its following example (lazy-seq
wrapping the map
) sucess?
Upvotes: 4
Views: 346
Reputation: 33657
The problem is using rest
in map operation. Basically when your lazy-seq will call the expression : (concat [0 1] (map + fib (rest fib)))
to return a ISeq object, the rest
call on fib will happen (as this is a parameter to map
it must be executed first and then passed to map and map is lazy but rest is called before we can reach lazyness). rest
will try to call more
on the fib which is a LazySeq
object and the more will cause the fib lazy seq to get the next ISeq which again involves the execution of whole concat
operation which involves rest
and it keeps on going this way until stack is blown away.
You need to use something that doesn't call next right away on the fib, something like drop
:
(def fib
(lazy-seq
(concat [0 1] (map + fib (drop 1 fib)))))
Also, in other case where lazy-seq
is inside concat
the rest
is not executed because it is wrapped inside a lazy-seq
operation which make the whole expression a function to be called in future when next ISeq is requested.
Hopefully this clear up things.
Upvotes: 3