whatever -> input -> whatever という reduce 関数に渡すような関数("reducing関数"と呼ばれる)を受け取ってreducing関数を返す関数、つまり
(whatever -> input -> whatever) -> (whatever -> input -> whatever)
のことを"transducer"と呼んでいる。
cf. https://japan-clojurians.github.io/clojure-site-ja/reference/transducers
例えば (map #(* % %)) は何らかの入力データの個々の要素(数値)を2乗するtransducer(= 2引数関数を受け取って2引数関数を返す高階関数)で、ここでは 仮に xform と名付けて conj に適用するとベクター、flipした cons に適用するとリスト、 str に適用すると文字列として出力できる。
dev> (def xform (map #(* % %)))
#'dev/xform
dev> (reduce (xform #(cons %2 %1)) () (range 10))
(81 64 49 36 25 16 9 4 1 0)
dev> (reduce (xform conj) [] (range 10))
[0 1 4 9 16 25 36 49 64 81]
dev> (reduce (xform #(cons %2 %1)) () (range 10))
(81 64 49 36 25 16 9 4 1 0)
dev> (reduce (xform str) "" (range 10))
"0149162536496481"
;; より簡潔に `transduce` 関数を利用すると
dev> (transduce xform conj [] (range 10))
[0 1 4 9 16 25 36 49 64 81]
dev> (transduce xform (fn ([] ()) ([coll] coll) ([coll x] (cons x coll))) () (range 10)) ; `cons` はreducing関数として定義が不十分なため工夫が必要
(81 64 49 36 25 16 9 4 1 0)
dev> (transduce xform str "" (range 10))
"0149162536496481"この例では出力データを切り替える一方で入力データはシーケンス固定だったが、入力データにも xform (transducer)は依存しないので、シーケンス以外にもstreamやchannelなど様々な入力を扱うことができる。