Вопрос

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?

Это было полезно?

Решение

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top