Jak przekonwertować sekwencję leniwą na nieleniwą w Clojure


95

Wypróbowałem następujące czynności w Clojure, spodziewając się, że zwrócona zostanie klasa nieleniwej sekwencji:

(.getClass (doall (take 3 (repeatedly rand))))

Jednak to wciąż powraca clojure.lang.LazySeq. Domyślam się, że doallocenia całą sekwencję, ale zwraca oryginalną sekwencję, ponieważ jest nadal przydatna do zapamiętania.

Więc jaki jest idiomatyczny sposób tworzenia nieleniwej sekwencji z leniwej?


Jestem zaskoczony, że nikt nie zapytał, dlaczego martwisz się o rzeczywisty typ zwracanej wartościdoall
tar

Możesz przekonwertować na wektor:(vec (take 3 (repeatedly rand)))
Kris

Odpowiedzi:


161

doallto wszystko czego potrzebujesz. Tylko dlatego, że seqtyp has LazySeqnie oznacza, że ​​oczekuje na ocenę. Leniwy zapisuje w seqpamięci swoje wyniki, więc wszystko, co musisz zrobić, to przejść seqraz leniwego (tak doallsamo jak ), aby wymusić to wszystko, a tym samym uczynić go nie leniwym. seqnie nie zmusi całą kolekcję do oceny.


2
Zmieniłem to na zaakceptowaną odpowiedź. A propos, za pomocą jakich środków możesz określić, czy LazySeq został wcześniej oceniony?
Tim Clemons

10
Wierzę, że po prostu zadzwoń realized?.
toofarsideways

1
Prawdopodobnie powinna istnieć odpowiednia realizeoperacja realized?.
Reut Sharabani

To wszystko jest bardzo miłe. Ale ponieważ niektóre funkcje, takie jak contains?nie dbają o to, czy zdałeś sobie sprawę z leniwej sekwencji, czy nie, to odpowiada na konkretne pytanie, które zostało zadane, ale mniej na tytuł pytania.
matanster

75

Do pewnego stopnia jest to kwestia taksonomii. leniwa sekwencja to tylko jeden typ sekwencji, podobnie jak lista, wektor czy mapa. Odpowiedź brzmi więc oczywiście „to zależy od tego, jakiego typu nie leniwą sekwencję chcesz uzyskać:
Wybierz spośród:

  • była leniwa (w pełni oceniona) leniwa sekwencja (doall ... )
  • lista dostępu sekwencyjnego (apply list (my-lazy-seq)) OR (into () ...)
  • wektor do późniejszego dostępu swobodnego (vec (my-lazy-seq))
  • mapę lub zestaw, jeśli masz jakiś specjalny cel.

Możesz mieć dowolny typ sekwencji, który najbardziej odpowiada Twoim potrzebom.


To najlepsza odpowiedź.
Felipe,

4
Przyjęta odpowiedź jest technicznie poprawna, ale ta odpowiedź była dla mnie najbardziej przydatna. Próbowałem zmapować funkcję na wektorze, a następnie wyplułem wyniki do pliku i nawet po wywołaniu doall plik zawierał „clojure.lang.LazySeq@address” zamiast zawartości sekwencji. Wezwanie vec na mapie wartości zwróciło mi to, co musiałem wypluć do pliku.
Jesse Rosalia

1
@JesseRosalia Dobrze wiedzieć, że jedyna odpowiedź Richa Hickeya w całej sprawie była poprawna technicznie. ;-)
Phil Cooper

(vec (my-lazy-seq))nie jest takie przyjemne w sytuacjach takich jak poniżej: (vec (json/parse-string "{\"foo\":\"bar\"}")) ;; => [["foo" "bar"]]Ponieważ cheshiredecyduje się na produkcję lazy-seq z(json/parse-string)
codeasone

Łagodzenie powyższego polegało na gorliwym użyciu(json/parse-string-strict)
codeasone

22

Wydaje się, że ten bogaty facet zna swój strój i ma całkowitą rację.
Ale myślę, że ten fragment kodu, używając twojego przykładu, może być przydatnym uzupełnieniem tego pytania:

=> (realized? (take 3 (repeatedly rand))) 
false
=> (realized? (doall (take 3 (repeatedly rand)))) 
true

Rzeczywiście typ się nie zmienił, ale realizacja zmieniła się


2
Warto jednak zauważyć, że nie musisz zmuszać całej sekwencji realized?do powrotu true. Np.(let [r (range) r? (realized? r)] (doall (take 1 r)) [r? (realized? r)]) => [false true]
Alex Coventry

22
Ten bogaty facet: D haha
Julian Krispel-Samsel

10
@nimrod :) gra słów miała być jednak w "hís clojure".
Peter

10
Dla tych, którzy nie wiedzą, „bogacz” wymyślił Clojure.
erturne

1
@AlexCoventry Twój przykład zwraca[true true]

7

Natknąłem się na tym wpisie na blogu o doalltym, że nie jest rekurencyjny. W tym celu stwierdziłem, że pierwszy komentarz w poście załatwił sprawę. Coś w rodzaju:

(use 'closure.walk)
(postwalk identity nested-lazy-thing)

Znalazłem to przydatne w teście jednostkowym, w którym chciałem wymusić ocenę niektórych zagnieżdżonych aplikacji, mapaby wymusić stan błędu.


5
(.getClass (into '() (take 3 (repeatedly rand))))

3
To okropny pomysł. Odwraca sekwencję wejściową.
amalloy

3
Oczywiście w tym przypadku odwrócenie wejścia nie robi różnicy, ponieważ są to tylko 3 losowe liczby .... :-)
mikera
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.