Clojure transducers.


;; transduce acts like reduce, but the order of evaluation is different:
;; it visits each element once, applying the transformation function
;; and the combining function.
;; (map inc) is a transformation function that will be applied to
;; a collection before reducing
(transduce (map inc) + '(0 1 2 3 4))

;; The result is the same as:
(reduce + (map inc '(0 1 2 3 4)))

;; but the order of evaluation is the same as (only one traversal):
;; note that we need the "seed" here, otherwise the first element
;; isn't incremented
(reduce #(+ %1 (inc %2)) 0 '(0 1 2 3 4))

;; transduce can also take a "seed":
(transduce (map inc) * 1 '(0 1 2 3 4))

;; this is equivalent to:
(reduce #(* %1 (inc %2)) 1 '(0 1 2 3 4))

;; using filter in a transducer:
(transduce (filter even?) conj '(0 1 2 3 4))

;; the same as:
(reduce #(if (even? %2) (conj %1 %2) %1) [] '(0 1 2 3 4))

;; note that using '() as the seed reverses the order:
(reduce #(if (even? %2) (conj %1 %2) %1) '() '(0 1 2 3 4))

;; 'into' can also be used as a transducing function:
(into [] (filter even?) '(0 1 2 3 4))

;; note that 'map' and 'filter' resolve the ambiguity of how the transform should be used:
(transduce (filter even?) conj '(0 1 2 3 4))
(transduce (map even?) conj '(0 1 2 3 4))

;; one can compose transforming functions (note the order: filter is applied first!):
(transduce (comp (filter even?) (map inc)) conj '(1 2 3))

;; it is common to save transforming functions in a variable:
(def xf (comp (map :a) (filter #(< % 2))))

(transduce xf conj '({:a 1} {:a -4 :b 2} {:a 5}))

;; there are other functions that can act as transforming functions:
;; take, drop, replace, keep, partition,....
;; There are also other functions, besides tarnsduce and into, that can act as
;; sequence, iteration.

CSci 4651 course web site.