Transducers are a generic and composable way to operate on a collection of values, producing a new value or new collection of new values. The word ‘transducer’ itself can be split into two parts that reflect this definition: ‘transform’ — to produce some value from another — and ‘reducer’ — to combine the values of a data structure to produce a new one.
Transducers are a composable way to build algorithmic transformations. We kind of do this already with
algorithmic transformations as map
, filter
, etc. combined with the usage of compose
.
But there are issues.
Array (or other collection) operations like map, filter and reverse can be defined in terms of a reduce.
[1,2,3,4].map(function (input) {
return input + 1;
}) // => [2,3,4,5]
[1,2,3,4].reduce(function (result, input) {
return result.concat([input + 1]);
}, []) // => [2,3,4,5]
A reducing function is any function that can be passed to reduce. They have the form:
(something, input) -> something
. They’re the inner-most function in the map and filter examples.
A map and filter function extracted out to be a reducing function:
const mapper = xf => {
return (acc, value) => {
return concat(acc, xf(value));
}
}
const filterer = predicate => reducer => {
return (acc, value) => {
if (predicate(value)) concat(acc, value)
return acc
}
}
function greaterThanTwo(x) {
return (x > 2);
}
function inc(x) {
return x + 1;
}
[1,2,3,4].reduce(mapper(inc), []) // => [2,3,4,5]
[1,2,3,4].reduce(filterer(greaterThanTwo), []) // => [3,4]