Reducers and transducers are consecutive refinements of the same functional abstraction. They are both based on reduce to provide improved collection processing. The focus is on parallelism in the case of reducers, while transducers mainly focus on reuse. They also bring to the table other improvements like better composability and improved performance. Transducers improve over reducers in terms of functional abstraction, but reducers offers extended parallelism. Here’s a summary of their main characteristics:
- Transducers can compose over the existing library functions like map or filter. Reducers require alternative implementations of the same functions.
- Transducers and reducers both compose with comp.
- Reducers can run in parallel using fold (although this works only on vectors, maps and r/foldcat objects). Transducers can still run in parallel on top of reducers with limitations around usable transducers (only stateless transducers work reliably in parallel).
- Both transducers and reducers apply multiple composed reducing functions during a "single pass" on the input collection. This differs from standard collection processing where each operation (like
clojure.core/map
orclojure.core/filter
) produces intermediate results.
- Both transducers and reducers are open for extension: specific collection types can define their own folding or transducing behaviors.
- Transducers can be used lazily while reducers always consume their input eagerly.