2013-08-27 13 views
7

Jestem obecnie czyta książkę programowania O'reilly Clojure które mówi, co następuje w to odcinek o leniwych sekwencje:Jak znaleźć długość leniwej sekwencji bez wymuszania realizacji?

Jest możliwe (choć bardzo rzadko) na leniwe sekwencji znać jego długości, a dlatego zwróć go w wyniku liczenia, nie zdając sobie sprawy z jego zawartości.

Moje pytanie brzmi: Jak to się robi i dlaczego jest tak rzadkie?

Niestety, książka nie określa tych rzeczy w tej sekcji. Osobiście uważam, że bardzo przydatna jest znajomość długości leniwej sekwencji przed jej wykonaniem, na przykład na tej samej stronie jest przykładem leniwej sekwencji plików, które są przetwarzane za pomocą funkcji używającej map. Byłoby miło wiedzieć, ile plików można przetworzyć przed wykonaniem sekwencji.

Odpowiedz

7

Przypuszczam, że to ze względu na fakt, że zazwyczaj istnieją inne sposoby, aby sprawdzić rozmiar.

Jedynym realizacja sekwencji mogę myśleć teraz, że potencjalnie może zrobić, jest pewnego rodzaju mapą kosztownej funkcji/procedurze nad znanej kolekcji size.

prosta implementacja powróci wielkości zbiorów bazowego, natomiast przesunięcie realizacji elementów lazy sekwencji (i w związku z tym wykonanie kosztownych części), nie jest to konieczne.

W takim przypadku jeden wie wielkość zbioru, który jest zmapowany na wcześniej i można użyć że zamiast leniwy nast wielkości.

Czasami może się to przydać, dlatego nie jest to możliwe, ale rzadko jest to konieczne.

+1

To oczywiście nie jest jedyny możliwy przykład. A co z '(powtórz 1000 razy)'? '(zakres 100)'? Istnieje wiele rodzajów leniwych sekwencji, które * mogą * znać ich długość, ale nie mają ich zaprogramowane w prosty sposób, ponieważ wymagałyby czasu inżynieryjnego i mają czas potrzebny na wykonanie pewnej niewielkiej przewagi. – amalloy

+0

@amalloy, dlatego powiedziałem "mogę myśleć", może powinienem był dodać "teraz" na końcu :) Nadal pozostaje reszta odpowiedzi - długość leniwej sekwencji jest znana przed jej utworzeniem, więc nie ma prawdziwy zysk w sprytnie realizującej długość w samej sekwencji. – soulcheck

+0

Czy to oznacza, że ​​niemożliwe jest policzenie bez wykonania leniwej sekwencji, która jest wynikiem "filtru"? Powiedz leniwą sekwencję kilku milionów liczb losowych: '(- >> my-rand-int-lazy-seq (filter # (nawet?%)) (Count-without-realizacji))'? – adamneilson

9

jako inspirowane przez soulcheck's answer, tutaj jest leniwy, ale liczy się mapa drogiego funkcji na zbiorze stałym rozmiarze.

(defn foo [s f] 
    (let [c (count s), res (map f s)] 
    (reify 
     clojure.lang.ISeq 
     (seq [_] res) 
     clojure.lang.Counted 
     (count [_] c) 
     clojure.lang.IPending 
     (isRealized [_] (realized? res))))) 


(def bar (foo (range 5) (fn [x] (Thread/sleep 1000) (inc x)))) 

(time (count bar)) 
;=> "Elapsed time: 0.016848 msecs" 
; 5 

(realized? bar) 
;=> false 


(time (into [] bar)) 
;=> "Elapsed time: 4996.398302 msecs" 
; [1 2 3 4 5] 

(realized? bar) 
;=> true 

(time (into [] bar)) 
;=> "Elapsed time: 0.042735 msecs" 
; [1 2 3 4 5] 
+0

+1 dla przykładowej implementacji – soulcheck

Powiązane problemy