2012-08-30 8 views
5

Running to działa zgodnie z oczekiwaniami:Jak mogę utworzyć leniwy nast wektor

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

Jednak chciałbym zrobić to samo z wektorem:

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

To daje mi stos przelewowy. Czemu?

Odpowiedz

8

Głównym powodem jest to, że wektory nie leniwe - tak połączenie into greedily zużywa cyklicznych sekwencje wytworzone long-seq-vec i powoduje przepełnienie komina. W związku z tym nie można utworzyć nieskończonego wektora (generalnie można utworzyć nieskończoną strukturę danych, jeśli jest leniwy lub cykliczny).

Działa w pierwszym przykładzie, ponieważ cons z przyjemnością zachowuje się leniwie, gdy znajduje się na przedzie leniwej sekwencji, więc sekwencja może być nieskończona.

Zakładając, że faktycznie chcą nieskończony ciąg wektorów sugeruję coś takiego:

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

lub alternatywnie można użyć for który jest leniwy w sobie:

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

I preferuj to, ponieważ omija płytę główną, unika rekursji i jest nieco bardziej wyraźny w wyrażaniu tego, co twoja funkcja ma ... jest trochę bardziej "deklaratywna", jeśli chcesz. W podobny sposób można również użyć numeru map.