> I summarised my issues with the different solutions. Since things got
> a bit philosophical I wrote up a short blog post on my point of view:
> http://bit.ly/hInw0J
I'm surprised to hear that partition-by is not very lazy, and will
hang on an infinite seq. Fortunately, that can be fixed:
(defn partition-by [f s]
(lazy-seq
(let [s (seq s)]
(if s
(let [fs (map f s)
eq (cons true (map = fs (rest fs)))
eqs (seq (map list eq s))
step (fn step [eqs]
(lazy-seq
(let [eqs (seq eqs)]
(if eqs
(cons
(lazy-seq
(cons (second (first eqs))
(map second (take-while first (rest eqs)))))
(step (drop-while first (rest eqs))))))))]
(step eqs))))))
A bit long and convoluted, with no fewer than three applications of
lazy-seq, but fully lazy:
user=> (defn report-seq
[]
(letfn [(this
[i]
(lazy-seq
(prn (str ">" i "<"))
(cons i (this (inc i)))))]
(take 14 (this 0))))
#'user/report-seq
user=> (def q (partition-by #(quot % 3) (report-seq)))
#'user/q
; No elements realized
user=> (def q (first (partition-by #(quot % 3) (report-seq))))
">0<"
#'user/q
; Had to realize 0 to know whether to return nil or a lazy-seq object here
user=> (def q (first (first (partition-by #(quot % 3) (report-seq)))))
">0<"
#'user/q
; Realized only the element it returned
user=> (def q (second (partition-by #(quot % 3) (report-seq))))
">0<"
">1<"
">2<"
">3<"
; Realized up to the first element of the next chunk, to know if that
; chunk existed
user=> (partition-by #(quot % 3) (report-seq))
">0<"
((0">1<"
1">2<"
2">3<"
) (3">4<"
4">5<"
5">6<"
) (6">7<"
7">8<"
8">9<"
) (9">10<"
10">11<"
11">12<"
) (12">13<"
13))
; Each element realized only as it's needed during a full traversal
user=> (take 5 (partition-by #(quot % 3) (iterate inc 0)))
((0 1 2)
(3 4 5)
(6 7 8)
(9 10 11)
(12 13 14))
; Does not blow up on infinite input seq
user=> (defn report-fn [x] (println "Expensive computation would have
been run on: " x) (quot x 3))
#'user/report-fn
user=> (def q (doall (map doall (partition-by report-fn (range 14)))))
Expensive computation would have been run on: 0
Expensive computation would have been run on: 1
Expensive computation would have been run on: 2
Expensive computation would have been run on: 3
Expensive computation would have been run on: 4
Expensive computation would have been run on: 5
Expensive computation would have been run on: 6
Expensive computation would have been run on: 7
Expensive computation would have been run on: 8
Expensive computation would have been run on: 9
Expensive computation would have been run on: 10
Expensive computation would have been run on: 11
Expensive computation would have been run on: 12
Expensive computation would have been run on: 13
#'user/q
; The potentially-expensive f is only run once per item during a full traversal
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en