I find this quite interesting because Meikel has effectively created a faster version of reductions:
(defn cumulative ([accum-fn s] (rest (cumulative accum-fn 0 s))) ([accum-fn accum s] (lazy-seq (when-let [[f & r] (seq s)] (cons accum (cumulative accum-fn (accum-fn accum f) r)))))) (defn left-total [coll] (map list coll (cumulative + 0 coll))) I did some microbenchmarking and it does appear to be 2x as fast as reductions, and processes the special case left-total just as fast as one of the original proposals. Oddly left-tot2 performs very poorly though it was claimed to be fast. I suppose this could be yet another case of microbenchmarking being evil - but looking at the code the reductions version seems to use an atom which implies some unnecessary overhead? Or maybe I am missing something important about their differences. I followed the link to the discussion about the original reductions and it all seems to be pre-lazy-seq so maybe this is just a case of the function should be updated? Below are the timing results (don't recommend basing anything off them as just adhoc) user=> (time (dotimes [i 10000000] (left-total3 coll))) "Elapsed time: 1460.309131 msecs" nil user=> (time (dotimes [i 10000000] (left-total3 coll))) "Elapsed time: 1600.225655 msecs" nil user=> (time (dotimes [i 10000000] (left-total2 coll))) "Elapsed time: 960.000014 msecs" nil user=> (time (dotimes [i 10000000] (left-total2 coll))) "Elapsed time: 957.096643 msecs" nil user=> (time (dotimes [i 10000000] (left-total coll))) "Elapsed time: 702.240509 msecs" nil user=> (time (dotimes [i 10000000] (left-total coll))) "Elapsed time: 685.018973 msecs" nil user=> (time (dotimes [i 10000000] (left-total3 coll))) "Elapsed time: 1492.383251 msecs" nil user=> (time (dotimes [i 10000000] (left-total coll))) "Elapsed time: 719.915803 msecs" nil user=> (time (dotimes [i 10000000] (left-tot2 coll))) "Elapsed time: 10286.935494 msecs" (defn left-total2 [lst] (let [tot (atom 0)] (map (fn [cur] (let [old-tot @tot] (swap! tot (partial + cur)) [cur old-tot])) lst))) (use 'clojure.contrib.seq-utils) (defn left-total3 [coll] (map list coll (reductions + 0 coll))) (defn left-tot2 [lst] (loop [result [ ] tot 0 terms lst] (if (empty? terms) result (let [f (first terms)] (recur (conj result [f tot]) (+ tot f) (rest terms)))))) 2009/12/29 Conrad <drc...@gmail.com>: > Thanks Meikel- Let me see if I understand what's going on here... > > Usually, calling "left-total" recursively from a non-tail call > position, as you do in this example, would abuse the call stack. > However, since the call is happening from within a lazy-seq, does this > mean the number of items on the call stack will remain unhindered, > despite the non-tail-call recursion? > > Experimentally, this version seems to perform as well as any of my > solutions (under 2 secs for 1 mil items) This suggests it is, indeed, > not causing any abuse of the call stack. > > This is definitely cleaner and more flexible than any other solution > suggested so far, I think. > > On Dec 28, 9:11 am, Meikel Brandmeyer <m...@kotka.de> wrote: >> Hi, >> >> Am 28.12.2009 um 02:36 schrieb Conrad: >> >> > => (left-total [3 5 10 1 2 7]) >> > ([3 0] [5 3] [10 8] [1 18] [2 19] [7 21]) >> >> If in doubt, use lazy-seq. >> >> (defn left-total >> [accum-fn accum s] >> (lazy-seq >> (when-let [[f & r] (seq s)] >> (cons [f accum] (left-total accum-fn (accum-fn accum f) r))))) >> >> user=> (left-total + 0 [3 5 10 1 2 7]) >> ([3 0] [5 3] [10 8] [1 18] [2 19] [7 21]) >> >> Since you said, that + is more complicated in your specific case, you might >> want this more general form. Otherwise the above can of course be simplified… >> >> Sincerely >> Meikel > > -- > 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 -- 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