Created
October 16, 2020 20:41
-
-
Save KingCode/8970fe4e2308127ba467ac7f57d3f78b to your computer and use it in GitHub Desktop.
Hand rolled sequence to prevent chunking
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn lazify [[x & xs :as coll]] | |
(lazy-seq | |
(when (seq coll) | |
(cons x (lazify xs))))) | |
(def my-lazy-input (lazify [1 2 4 1 2 3 1])) | |
(type my-lazy-input) ;; => clojure.lang.LazySeq | |
(type (rest my-lazy-input)) ;; => clojure.lang.LazySeq | |
;; So my-lazy-input is truly lazy all the wal...Now I want to feed it to 'sequence | |
;; with a reducing fn which increments and weeds out duplicates, and would like to | |
;; preserve the same degree of lazyness: | |
(def not-lazy (sequence (comp (map inc)) my-lazy-input)) | |
(type not-lazy);; => clojure.lang.LazySeq so far so good! | |
(type (rest not-lazy)) ;; => clojure.lang.ChunkedCons, ooops wanted lazy all the way | |
(type (rest (rest not-lazy)));; => clojure.lang.ChunkedCons | |
;; Hand rolled sequence fn to keep laziness | |
(defn hand-rolled-sequence [xs task init] | |
(let [start (fn g [[x & xs :as coll] state] | |
(lazy-seq | |
(when (seq coll) | |
(let [[emit? next-state res] (task state x)] | |
(if emit? | |
(cons res | |
(g xs next-state)) | |
(g xs next-state))))))] | |
(start xs init))) | |
(def two-to-five (hand-rolled-sequence | |
[1 2 4 1 2 3 1] | |
(fn [seen x] | |
(let [x+ (inc x)] | |
(if (seen x+) | |
[false seen nil] | |
[true (conj seen x+) x+]))) | |
#{})) | |
(type two-to-five) ;; clojure.lang.LazySeq | |
(type (rest two-to-five)) ;; clojure.lang.LazySeq | |
(realized? (rest two-to-five)) ;; false | |
(take 4 two-to-five) ;; (2 3 5 4) | |
(type (rest (rest (rest two-to-five)))) ;; clojure.lang.LazySeq all the way |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment