Search code examples
clojuretransducer

Transducer's init not called


I am writing a custom transducer as an exercise, but I am surprised to see that its 0-arity init function is not called.

Why?

Is it related to which aggregation function I am using? If yes, which ones would call the init function and why others are not?

(defn inc-xf [xf]
  "inc-xf should be equivalent to (map inc)"
  (fn
    ;; init
    ([]
     (println "init") ;; <- this is not called (???)
     (xf))

    ;; step
    ([result input]
     (println "step" result input)
     (xf result (inc input)))

    ;; completion
    ([result]
     (println "completion" result)
     (xf result))))

(transduce inc-xf
           +
           100
           [5 5 5])

Solution

  • If you look at the implementation of transduce you can see what happens.

    (defn transduce
      ;; To get the init value, (f) is used instead of ((xform f))
      ([xform f coll] (transduce xform f (f) coll))
      ([xform f init coll]
       ,,,))
    

    Why, however, is more difficult to answer.

    Transducers implementing the zero arity is part of the requirements for a transducer, but it is never actually used in any transducing context in clojure.core. On the mailing list there's been a post asking the same question as you and proposal of an implementation of transduce that actually uses the init arity. The jira ticket was declined, however, with the explanation:

    Rich asked me to decline the ticket because the init arity of the xform should not be involved in the reducing function accumulation. - Alex Miller

    Why, then, is the init arity part of the contract for a transducer if it's not used anywhere? ¯\_(ツ)_/¯