With new clojure 1.7 I decided to understand where I can use transducers. I understand what benefit they can give, but I can't find normal examples of writing custom transducers with explanation.
Ok, I tried to test what is happening. I opened the clojure documentation. And there examples use xf
as argument. First: what means this xf or xfrom?
This stuff produced identity transducer.
(defn my-identity [xf]
(fn
([]
(println "Arity 0.")
(xf))
([result]
(println "Arity 1: " result " = " (xf result))
(xf result))
([result input]
(println "Arity 2: " result input " = " (xf result input))
(xf result input))))
I took the naming of variables [result input]
from documentation example.
I thought it's like in reduce function where result
is reduced part and input
is new collection element.
So when I make (transduce my-identity + (range 5))
I got result 10
what I was expecting.
Then I read about eduction
, but I can't understand what is it. Anyway
I made (eduction my-identity (range 5))
and got:
Arity 2: nil 0 = nil
Arity 2: nil 1 = nil
Arity 1: nil = nil
(0 0 1 1)
Every item got duplicated because I call xf
in println
statement.
Why it duplicated every item twice?
Why I got nil?
Will I always get nil while making an eduction?
Can I relay on this behavior?
Anyway I did
> (reduce + (eduction my-identity (range 5))
clojure.core.Eduction cannot be cast to clojure.lang.IReduce
Ok, the result is a Eduction
that is NOT reducible, but printed like a list. Why it is not reducible? When I type (doc eduction)
I get that
Returns a reducible/iterable application of the transducers
to the items in coll.
Shouldn't (transduce xform f coll)
and (reduce f (eduction xfrom coll))
be the same?
I made
> (reduce + (sequence my-identity (range 5))
20
Of course I got 20
because of duplicates. Again I thought it should be
that (transduce xform f coll)
and (reduce f (sequence xfrom coll))
be
always equal at least in such small example without any stateful transducers. This is stupid that they are not, or I'm wrong?
Ok, then I tried (type (sequence my-identity (range 5)))
and get
clojure.lang.LazySeq
I thought, that it's lazy but when I tried to take the first
element
clojure calculated all the sequence at once.
So my summary:
1) What means xf or xform?
2) Why I get nil
as a result
argument while eduction
or sequence
?
3) Could I always be sure that it will be nil
while eduction
or sequence
?
4) What is eduction
and what is the idiomatic idea it's not reducible? Or if it is, then how I can reduce it?
5) Why I get side effects while sequence
or eduction
?
6) Can I create actual lazy sequences with transducers?
xf
– birdspiderxf
' – birdspider