How to use LazySeq correctly

There are a dozen confusions when I use lazySeq.

Question:

(def fib (lazy-seq (concat [0 1] (map + fib (rest fib))))) ;; It Ok (take 10 fib) ;; Bomb 

Received error message: StackOverflowError clojure.lang.RT.more (RT.javahaps89)

And the following solutions work 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 a lazy sequence, why are the above programs similar to each other but distinguish?

In more detail: why the first example ( lazy-seq wrapping concat ) fails, but its next example ( lazy-seq wrapping map ) sucess?

+4
source share
1 answer

The problem is using rest in map operations. Basically, when your lazy-seq calls the expression: (concat [0 1] (map + fib (rest fib))) to return the ISeq object, a call to rest will be made on the feed (since this is a map parameter, it must be executed first, and then transferred to the card and the card is lazy, but the rest is called before we can achieve laziness). rest will try to call more in the fib, which is the LazySeq object, and the more it will cause the lazy seq to get the next ISeq, which again turns on the whole concat operation, which includes rest , and it continues to go this way while the stack not blown away.

You need to use something that doesn't immediately follow the feed, something like drop :

 (def fib (lazy-seq (concat [0 1] (map + fib (drop 1 fib))))) 

In addition, in another case, when lazy-seq is inside concat , rest not executed, because it is wrapped inside the lazy-seq operation, which makes the whole expression a function that will be called in the future when the next ISeq is requested.

Hope this clarifies the situation.

+3
source

All Articles