5

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.

sumek
  • 26,495
  • 13
  • 56
  • 75

2 Answers2

10

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.

Community
  • 1
  • 1
JustAnotherCurious
  • 2,208
  • 15
  • 32
3

Just to add a use case for eductions to @JustAnotherCurious' great explanation.

An eduction allows you to bundle one or more transducers with the collection to be transduced, into something that can be reduced, but eduction does not perform any transductions.

transduce in contrast, actually reduces the collection, using the specified transducer and a reducing function.

I use eductions in code that creates or knows about the transducers and the collection of some operation, but needs to stay agnostic of the reducing function. So I can pass the result of an eduction around as a single unit, and use it someplace the reduction function is known to reduce it.

This can help you keep your aspects separated (more orthogonal code) and lead to cleaner code.

Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156