W docstrings dla first
i rest
powiedzieć, że funkcje te nazywają seq
na swoich argumentów, aby przekazać ideę, że nie trzeba zadzwonić seq
się przechodząc w seqable kolekcji, która nie jest sama w sobie nast, jak mówią , wektor lub zestaw. Na przykład,
(first [1 2 3])
;= 1
nie będzie działać, jeśli first
nie zadzwonił seq
na swojej argumentacji; zamiast tego trzeba byłoby powiedzieć, że byłoby to niewygodne.
Zarówno take
, jak i drop
również wywołują w swoich argumentach seq
, w przeciwnym razie nie można ich wywołać na wektorach itp., Jak wyjaśniono powyżej. W rzeczywistości dotyczy to wszystkich standardowych kolekcji seq - te, które nie nazywają się seq
, są bezpośrednio zbudowane na komponentach niższego poziomu.
W żaden sposób nie osłabia to lenistwa leniwych seqs. Wymuszenie/wykonanie, które dzieje się w wyniku połączenia first
/rest
, jest najmniejszą możliwą do uzyskania żądanym wynikiem. (Ile to zależy od rodzaju argumentu, jeśli w rzeczywistości nie jest leniwy, nie ma dodatkowej realizacji związanej z rozmową first
, jeśli jest częściowo leniwy - to znaczy, porwany - będzie trochę dodatkowych realizacja (do 32 elementów początkowych zostanie obliczonych od razu), jeśli jest w pełni leniwy, tylko pierwszy element zostanie obliczony.)
Najwyraźniej first
, po przejściu leniwego seq, musi wymusić realizację swojego pierwszego elementu - - o to chodzi. rest
jest rzeczywiście nieco leniwy, ponieważ faktycznie nie wymusza realizacji części "odpoczynku" seq (to w przeciwieństwie do next
, która jest zasadniczo równoważna z (seq (rest ...))
). Fakt, że zmusza pierwszy element do realizacji, aby mógł go natychmiast pominąć, jest świadomym wyborem projektu, który unika niepotrzebnego nakładania warstw leniwych obiektów i trzymania główki oryginalnego seq; możesz powiedzieć coś takiego, jak (lazy-seq (rest xs))
, aby odroczyć nawet tę początkową realizację, kosztem utrzymania się na xs
, dopóki nie zostanie zrealizowane opakowanie lazy seq.
Dzięki za to. Sądzę, że to różnica między tym, co za dużo, a tym, co w pełni leniwe, rzuciła mnie. W szczególności, gdy pracowałem najpierw z leniwym seqem, myślę, że wszystko, nad czym pracowałem, musiało powodować problemy podczas dzielenia, więc utknąłem po tym. – robertjlooby
Tak, chunking może prowadzić do nieoczekiwanych rezultatów, jeśli ktoś o tym zapomni. 'take' używa zarówno' first' jak i 'rest' w swojej implementacji, natomiast' drop' jest wbudowane w 'rest', więc nie pomagają.Unchunking jest możliwy, ale tylko w tym sensie, że można dokonać transformacji ułożonych na wierzchu fragmentów kawałków, aby ocenić jeden element na raz; leżące u jego podstawy seq zawsze zrealizuje jego porcje w całości. (Sposób na zrobienie tego to owijanie seq w niezakładane seq, być może wyprodukowane z '(reify clojure.lang.IScheq ...)' z oryginalnym seq w zamknięciu.) –
Jesteś pewny 'take'/'drop' również nazywa się' seq'? Po prostu wypróbowanie go w repl i wywołanie 'class' z' (range) ',' (take 1 (range)) ',' (drop 1 (range)) 'all daje' clojure.lang.LazySeq'. Wywołanie z '(reszta (zakres))', '(seq (zakres)) daje' clojure.lang.ChunkedCons'. – robertjlooby