clojuretransducer

eduction vs transducer composition


Whats the difference between:

(transduce (comp fn-1 fn-2 fn-3) conj vector-collection)

and

(eduction fn-1 fn-2 fn-3 vector-collection)

I've read the eduction docs but didn't understand the purpose of the eduction.


Solution

  • transduce reduces the transducer by applying the reducing function to a collection. A result is calculated.

    eduction is just stuff that remembers that you want to apply a transducer to a collection. Eduction is not itself a collection in "regular sense", but implements it's interface. So when you try to print it, it print itself like sequential.

    Look here:

    (defn my-tran [rf]
      (fn
        ([]
         (println "Arity 0!")
         (rf))
        ([res]
         (println "Arity 1!")
         (rf res))
        ([result input]
         (println "Arity 2!")
         (rf result input))))
    
    > (def a (transduce my-tran conj '(1 2 3)))
    Arity 2!
    Arity 2!
    Arity 2!
    Arity 1!
    #'test.core/a ;a is already finished
    
    > (def r (eduction my-tran '(1 2 3)))
    #'test.core/r ;nothing was done
    > r 
    Arity 2!
    Arity 2!
    Arity 2!
    Arity 1!
    (1 2 3) ;now it's done. Next call with calculate it again. Check it.
    > (sequential? r)
    true
    

    So eduction is a partial apply of the transducer to a collection without a reducing function. But it's not lazy-seq. So when you transduce or reduce over eduction it is the same (in the sense that the same job is done at this moment, not in the sense of the result) as if you called transduce with a reducing function to the original collection.

    See this: Clojure transducers behavior, where there is exceptional answer which covers many questions about this idea.