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?