To make our composition more readable and easier to name we are going to ceate a compose
function we can use to avoid having to manually nest our transducer calls.
We'll also go over semantically naming your compose
functions for extra readability.
Nested style:
import {doubleTheNumber, evenOnly} from "../utils"; const map = xf => reducer => { return (accumulation, value) => { return reducer(accumulation, xf(value)); }; }; const filter = predicate => reducer => { return (accumulation, value) => { if (predicate(value)) return reducer(accumulation, value); return accumulation; }; }; const isEvenFilter = filter(evenOnly); const isNot2Filter = filter(val => val !== 2); const doubleMap = map(doubleTheNumber); const pushReducer = (accumulation, value) => { accumulation.push(value); return accumulation; }; [1,2,3,4].reduce(isNot2Filter(isEvenFilter(doubleMap(pushReducer))), []);
Compose function:
import {filter, map, evenOnly, doubleTheNumber} from "../utils"; const doubleMap = map(doubleTheNumber); const isEvenFilter = filter(evenOnly); const isNot2Filter = filter(val => val !== 2); const pushReducer = (accumulation, value) => { accumulation.push(value); return accumulation; }; [1, 2, 3, 4].reduce(isNot2Filter(isEvenFilter(doubleMap(pushReducer))), []); // compose(f,g)(x) === f(g(x)); // // compose(isNot2Filter, isEvenFilter, doubleMap)(pushReducer) === // isNot2Filter(isEvenFilter(doubleMap(pushReducer))); const compose = (...functions) => functions.reduce((accumulation, fn) => (...args) => accumulation(fn(...args)), x => x); [1, 2, 3, 4].reduce( compose(isNot2Filter, isEvenFilter, doubleMap)(pushReducer), [], ); /*?*/