Hi All, I’d like to offer an alternative implementation of clojure.core/transduce.
(I’ve done some searching, and I didn’t find any evidence that this has been raised before, but my apologies if I missed anything.) This alternative is best motivated by example. Consider the following transducers: (defn init-with [x] (fn [rf] (fn ([] (rf (rf) x)) ([result] (rf result)) ([result input] (rf result input))))) (defn complete-with [x] (fn [rf] (fn ([] (rf)) ([result] (rf (rf result x))) ([result input] (rf result input))))) (defn dupl [] (fn [rf] (fn ([] (rf)) ([result] (rf result)) ([result input] (rf (rf result input) input))))) I have selected these as each illustrate something ‘interesting’ occurring in each of the three arities of the reducing functions produced. Now consider the following transducer, which transforms numeric reducing functions. (def xform (comp (map inc) (complete-with 10) (map inc) (init-with 100) (map inc) (dupl))) The current behavior of transduce (and into, for illustration purposes) is: (into [37] xform (range 5)) ;=> [37 3 3 4 4 5 5 6 6 7 7 12 12] (transduce xform + 37 (range 5)) ;=> 111 (reduce + (into [37] xform (range 5))) ;=> 111 (transduce xform + (range 5)) ;=> 74 So the dupl and complete-with transducers work as I expected, but the init-with does not. What I was hoping for was: ;=> [37 101 101 3 3 4 4 5 5 6 6 7 7 12 12] ;=> 313 ;=> 313 ;=> 276 This is because transduce and into are currently implemented as something equivalent to the following: (defn curr-transduce ([xform f coll] (transduce xform f (f) coll)) ([xform f init coll] (let [rf (xform f)] (rf (reduce rf init coll))))) (defn curr-into [to xform from] (curr-transduce xform conj to from)) In the first arity of transduce, the initial value is taken from the reducing function f, not the reducing function produced by (xform f). And in the second arity, the supplied initial value is supplied directly to the reduction. These both bypass the transducer xform entirely, so the zeroth-arity is never invoked and no transformation occurs. I would like to propose the following alternative implementation: (defn alt-transduce ([xform f coll] (let [rf (xform f)] (rf (reduce rf (rf) coll)))) ([xform f init coll] (let [rf (xform (fn ([] init) ([result] (f result)) ([result input] (f result input))))] (rf (reduce rf (rf) coll))))) In the first arity, the initial value is drawn from the transformed reducing function, rather than the supplied reducing function. In the second arity, a reducing function is constructed from f and init to be f in arity 1 and 2, but return init in arity 0. Both cases ensure that the transducer is used to transform all three components of the reduction: init, step, and completion. Because of the way that the second arity is implemented, into doesn’t need to change: (defn alt-into [to xform from] (alt-transduce xform conj to from)) The effect is that the reducing function passed to xform is conj, except in arity 0, where the `to` collection is returned. These return the results I was originally expecting: (alt-into [37] xform (range 5)) ;=> [37 101 101 3 3 4 4 5 5 6 6 7 7 12 12] (reduce + (alt-into [37] xform (range 5))) ;=> 313 (alt-transduce xform + 37 (range 5)) ;=> 313 (alt-transduce xform + (range 5)) ;=> 276 I went though the list of transducers currently provided in clojure.core and none of them do anything ‘interesting’ in zeroth-arity init component, so the alternate implementation would not change their observable behavior. This only affects transducers that do something other than the trivial implementation of the zero-arity. The discussion https://groups.google.com/d/topic/clojure/M-13lRPfguc/discussion was the only related one I could find. Thanks, Dan -- 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.