Hi friends! For writing a lazy-seq which of this implementations is preferred?
;; wrap the tail
(defn drop-after
[p? s]
(when (seq s)
(let [head (first s)]
(if (p? head)
[head]
(cons head (lazy-seq (drop-after p? (rest s))))))))
;; wrap everything
(defn drop-after
[p? s]
(lazy-seq
(when (seq s)
(let [head (first s)]
(if (p? head)
[head]
(cons head (drop-after p? (rest s))))))))This is not correct
Sorry, I was wrong, but I was almost right. I've read this article https://stuartsierra.com/2015/04/26/clojure-donts-concat then I asked my self what if only wrap the tail. I didn't realized, that the head is always realized, but the tail will blowup anyway.
(defn concat-tail [x y]
(if (seq x)
(cons (first x)
(lazy-seq (concat-tail (rest x) y)))
y))
(defn concat-all [x y]
(lazy-seq
(if (seq x)
(cons (first x)
(concat-all (rest x) y))
y)))
(defn build-result [n cat]
(loop [counter 1
results []]
(if (< counter n)
(recur (inc counter)
(cat results (range 1 counter)))
results)))
(do (seq (build-result 4000 concat-all))
nil) ;; stackoverflow
(do (seq (build-result 4000 concat-tail))
nil) ;; it's ok
(->> (build-result 4000 concat-all)
(take 1)) ;; stackoverflow
(->> (build-result 4000 concat-tail)
(take 1)) ;; it's ok
(->> (build-result 4000 concat-all)
(take 2)) ;; stackoverflow
(->> (build-result 4000 concat-tail)
(take 2)) ;; stackoverflow blows up anywayhowdy! on the subject of lazy-seq "wrap everything vs wrap tail"
I recently find out that wrapping everything may cause stackoverflow when interleaving and concating lazy sequences, while wrapping the tail does not.
if everything is wrap when doing a
(seq some-lazy-seq) causes the whole seq to be realized combining lazy-sequences, while if only the tail is wrap (seq (cons h some-lazy-seq)) wont realized the whole seq.Also destructuring
(let [[h & t] some-lazy-seq] ...)causes the seq to be realized, I think the macro expansion introduces a call to seq .