Transducers

;; A transducer is a composable transformation, independent of input and output sources
(def xf (comp (filter odd?)
              (map inc)
              (take 3)))

(into [] xf (range 20))                ; [2 4 6]
(transduce xf + (range 20))            ; 12
(sequence xf (range 20))               ; (2 4 6): lazy
(eduction xf (range 20))               ; reducible/iterable, recomputed on each use
(transduce (map count) + ["a" "bb" "ccc"])   ; 6

;; Most sequence functions return a transducer when called without a collection:
;; map filter remove keep mapcat take take-while drop drop-while partition-by partition-all
;; dedupe distinct cat interpose replace halt-when random-sample

(into #{} (comp cat (map keyword)) [["a" "b"] ["c"]])   ; #{:a :b :c}

;; Benefits: no intermediate collections, reusable across collections/channels/streams
;; core.async channels accept transducers: (chan 10 (filter even?))

;; Writing a transducer
(defn my-map [f]
  (fn [rf]
    (fn
      ([] (rf))
      ([result] (rf result))
      ([result input] (rf result (f input))))))
(into [] (my-map #(* 10 %)) [1 2 3])   ; [10 20 30]

;; reduced: early termination
(reduce (fn [acc x] (if (> acc 10) (reduced acc) (
…