How can I create a lazy-seq vector

点点圈 提交于 2019-12-10 14:16:39

问题


Running this works as expected:

(defn long-seq [n]
  (lazy-seq (cons 
             (list n {:somekey (* n 2)})
             (long-seq (+ n 1)))))
(take 3 (long-seq 3))
; => ((3 {:somekey 6}) (4 {:somekey 8}) (5 {:somekey 10}))

However I would like to do the same thing with a vector:

(defn long-seq-vec [n]
  (lazy-seq (into 
             (vector (list n {:somekey (* n 2)}))
             (long-seq-vec (+ n 1)))))
(take 3 (long-seq-vec 3))

This gives me a stack overflow. Why?


回答1:


The main reason is that vectors aren't lazy - so the into call greedily consumes the recursive sequences produced by long-seq-vec and results in a stack overflow. As a corollary of this, it's not possible to create an infinite vector (in general, you can only create an infinite data structure if it is lazy or cyclic).

It works in the first example because cons is quite happy to behave lazily when consing onto the front of a lazy sequence, so the sequence can be infinite.

Assuming you actually want an infinite sequence of vectors I'd suggest something like:

(defn long-seq-vec [n]
  (lazy-seq (cons 
              (vector n {:somekey (* n 2)})
              (long-seq-vec (+ n 1)))))

(take 3 (long-seq-vec 3))

=> ([3 {:somekey 6}] [4 {:somekey 8}] [5 {:somekey 10}])

Or as an alternative, you can use for which is lazy in itself:

(defn long-seq-vec [n]
  (for [x (iterate inc n)]
    (vector x {:somekey (* x 2)})))

I prefer this as it avoids the lazy-seq/cons boilerplate, avoids recursion and is slightly more clear in expressing what your function does... it's a little more "declarative" if you like. You could also use map in a similar way.



来源:https://stackoverflow.com/questions/12206806/how-can-i-create-a-lazy-seq-vector

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!