> 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 clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to