2012-08-30 25 views
5

運行此按預期工作:如何創建一個懶惰-seq的矢量

(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})) 

但是我希望做一個向量同樣的事情:

(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)) 

這給了我一疊溢出。爲什麼?

回答

8

的主要原因是,向量不懶惰 - 這樣的into呼叫貪婪地消耗由long-seq-vec並且導致堆棧溢出產生的遞歸序列。作爲這種推論的結果,創建無限向量是不可能的(一般來說,如果它是懶惰或循環的,你只能創建一個無限的數據結構)。

它在第一個例子中起作用,因爲cons非常樂意在懶惰序列的前面表現得很懶惰,所以序列可以是無限的。

假設你真的想我會建議像載體的無限序列:

(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}]) 

或者作爲替代,你可以使用for這是懶惰的本身:

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

我寧願這樣做,因爲它避免了lazy-seq/cons樣板文件,避免了遞歸,並且在表達你的函數時會稍微清晰一些......如果你願意的話,它更具「聲明性」。您也可以以類似的方式使用map