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.
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.
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.
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 reduce
d, 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.