Recursive xforms – recursive transducers and reducers for the Clojure programming language.
Clojure 1.7 introduced transducers, which are functions that take a reducer function and returns a reducer function. This in itself sounds straightforward enough, but a lot of additional complexity was added to support stateful reducers.
The ones coming from take, drop, partition-by and similar. Whereas stateful reducers were available pre 1.7, they were frowned upon; you could (usually) assume that if you could use a function for reducing, then you could use it repeatedly, without surprings results. However, as with 1.7, a reducing function cannot be assumed to be stateless anymore:
;; A transducer is reducer -> reducer, so this is a reducer, right? user=> (def vec10 ((take 10) conj)) #'user/vec10 user=> (reduce vec10  (range 20)) [0 1 2 3 4 5 6 7 8 9] user=> (reduce vec10  (range 20)) 
In addition, there are strange mismatches between transducers and reducers, which initially does not seem to make much sense:
;; (reduce rf coll) != (transduce identity rf coll) user=> (reduce conj (range 10)) ClassCastException java.lang.Long cannot be cast to clojure.lang.IPersistentCollection clojure.core/conj--4338 (core.clj:82) user=> (transduce identity conj (range 10)) [0 1 2 3 4 5 6 7 8 9] ;; (reduce rf (rf) coll) != (transduce identity rf coll) (def rf-conj! (completing conj! persistent!)) user=> (reduce rf-conj! (rf-conj!) (range 10)) #object[clojure.lang.PersistentVector$TransientVector 0x2251dd42 "clojure.lang.PersistentVector$TransientVector@2251dd42"] user=> (transduce identity rf-conj! (range 10)) [0 1 2 3 4 5 6 7 8 9]
Rexf attempts to make it possible to actually call transducers yourself, by
setting up a level of indirection. In rexf, transducers take a ReducerFactory
and produces a ReducerFactory, and a ReducerFactory is a value that can
initialise a reducer by calling
rexf/init on it. You can also
This is an experiment, and may or may not make sense. See Recursive Transducers for the rationale.
Copyright © 2015 Jean Niklas L'orange
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.