Eduction retains the ability to be recomposed with other transducers higher in the function chain. The following two are nearly equivalent: (transduce (take 1e2) + (eduction (filter odd?) (range))) (transduce (comp (filter odd?) (take 1e2)) + (range))
This will be slower: (transduce (take 1e2) + (sequence (filter odd?) (range))) Execution time mean : 19.054407 µs Execution time mean : 19.530890 µs Execution time mean : 39.955692 µs I also wonder to what extent eduction can be used as a drop in replacement for sequence. On Wednesday, April 1, 2015 at 9:13:07 AM UTC+2, Tassilo Horn wrote: > > Hi all, > > I've switched many nested filter/map/mapcat applications in my code to > using transducers. That brought a moderate speedup in certain cases > and the deeper the nesting has been before, the clearer the transducers > code is in comparison, so yay! :-) > > However, I'm still quite unsure about the difference between `sequence` > and `eduction`. From the docs and experimentation, I came to the > assumptions below and I'd be grateful if someone with more knowledge > could verify/falsify/add: > > - Return types differ: Sequence returns a standard lazy seq, eductions > an instance of Eduction. > > - Eductions are reducible/sequable/iterable, i.e., basically I can use > them wherever a (lazy) seq would also do, so sequence and eduction > are quite interchangeable except when poking at internals, e.g., > (.contains (sequence ...) x) works whereas (.contains (eduction ...) > x) doesn't. > > - Both compute their contents lazily. > > - Lazy seqs cache their already realized contents, eductions compute > them over and over again on each iteration. > > Because of that, I came to the conclusion that whenever I ask myself if > one of my functions should return a lazy seq or an eduction, I should > use these rules: > > 1. If the function is likely to be used like > > (let [xs (seq-producing-fn args)] > (or (do-stuff-with xs) > (do-other-stuff-with xs) > ...)) > > that is, the resulting seq is likely to be bound to a variable > which is then used multiple times (and thus lazy seq caching is > benefitical), then use sequence. > > 2. If it is a private function only used internally and never with the > usage pattern of point 1, then definitively use eduction. > > 3. If its a public function which usually isn't used with a pattern as > in point 1, then I'm unsure. eduction is probably more efficient > but sequence fits better in the original almost everything returns > a lazy seq design. Also, the latter has the benefit that users of > the library don't need to know anything about transducers. > > Is that sensible? Or am I completely wrong with my assumptions about > sequence and eduction? > > On a related note, could someone please clarify the statement from the > transducers docs for `sequence`? > > ,----[ Docs of sequence at http://clojure.org/transducers ] > | The resulting sequence elements are incrementally computed. These > | sequences will consume input incrementally as needed and fully realize > | intermediate operations. This behavior differs from the equivalent > | operations on lazy sequences. > `---- > > I'm curious about the "fully realize intermediate operations" part. > Does it mean that in a "traditional" > > (mapcat #(range %) (range 10000)) > > the inner range is also evaluated lazy but with > > (sequence (mapcat #(range %)) (range 10000)) > > it is not? It seems so. At least dorun-ning these two expressions > shows that the "traditional" version is more than twice as fast than the > transducer version. Also, the same seems to hold for > > (eduction (mapcat #(range %)) (range 10000)) > > which is exactly as fast (or rather slow) as the sequence version. > > But wouldn't that mean that transducers with mapcat where the mapcatted > function isn't super-cheap is a bad idea in general at least from a > performance POV? > > Bye, > Tassilo > -- 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 unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.