2012-08-30 16 views
5

L'esecuzione di questo funziona come previsto:Come posso creare un pigro-ss vettore

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

Tuttavia vorrei fare la stessa cosa con un vettore:

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

Questo mi dà una pila troppo pieno. Perché?

risposta

8

La ragione principale è che vettori non sono pigri - quindi la chiamata into consuma avidamente le sequenze ricorsive prodotte da long-seq-vec e comporta un overflow di stack. Come corollario di questo, non è possibile creare un vettore infinito (in generale, è possibile creare una struttura di dati infinita solo se è pigro o ciclico).

Funziona nel primo esempio perché cons è piuttosto felice di comportarsi pigramente quando si trova sul fronte di una sequenza pigra, quindi la sequenza può essere infinita.

Supponendo che si vuole realmente una sequenza infinita di vettori Io suggerirei qualcosa di simile:

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

o in alternativa, è possibile utilizzare for che è pigro di per sé:

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

I preferisci questo in quanto evita lo lazy-seq/cons boilerplate, evita la ricorsione ed è leggermente più chiaro nell'esprimere ciò che fa la tua funzione ... è un po 'più "dichiarativo" se ti va. È anche possibile utilizzare map in modo simile.

Problemi correlati