Match Clojure's lazy seq realization model
jolt's seq layer realized one element ahead of Clojure, so a side-effecting lazy seq ran its producer too eagerly. Four changes bring it in line: - rest is Clojure's more(): it returns the tail without realizing it. An unforced tail (vector / string / lazy-seq cell) comes back as a deferred seq, so (rest (iterate f x)) does not call f. next still realizes one. - iterate applies f lazily, inside the tail thunk, so (first (iterate f x)) is x with no call to f (clojure.lang.Iterate parity). - take realizes exactly n: the last element terminates without touching the rest, instead of forcing one more element of the source. - an empty realized lazy seq is still a sequence value, printing "()" not "nil" (a JVM LazySeq is never nil). Also: the map transducer's step fn now takes multiple inputs ([result input & inputs]) so a multi-collection transduce applies f across all of them. Fixes medley's join/window/sequence-padded laziness and multi-input transducer tests (now 293/293). The rest change also fixed a latent overrun in distinct/dedupe over a map's empty tail. iterate is a seed source, re-minted.
This commit is contained in:
parent
331a41ee26
commit
448611a5df
6 changed files with 57 additions and 12 deletions
|
|
@ -96,8 +96,12 @@
|
|||
([n x] (take n (repeat x))))
|
||||
|
||||
;; --- iterate ---
|
||||
;; f is applied lazily, inside the tail thunk — (first (iterate f x)) is x with no
|
||||
;; call to f, matching clojure.lang.Iterate. Wrapping the whole body in lazy-seq
|
||||
;; instead would force (f x) the moment the head realizes (it is an eager argument
|
||||
;; to cons), realizing one step ahead.
|
||||
(defn iterate [f x]
|
||||
(lazy-seq (cons x (iterate f (f x)))))
|
||||
(cons x (lazy-seq (iterate f (f x)))))
|
||||
|
||||
|
||||
;; --- partition-all --- (transducer + [n coll] + [n step coll])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue