Skip to content

Instantly share code, notes, and snippets.

@KingCode
Created October 16, 2020 20:41
Show Gist options
  • Save KingCode/8970fe4e2308127ba467ac7f57d3f78b to your computer and use it in GitHub Desktop.
Save KingCode/8970fe4e2308127ba467ac7f57d3f78b to your computer and use it in GitHub Desktop.
Hand rolled sequence to prevent chunking
(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