Search code examples
javascriptfunctional-programmingreduceramda.jstransducer

Converting Reducer To Tranducer With Ramda


The following function reduceIfEven uses a predicate to check the value the reducer function receives for every step. If the predicate returns true, the value is added to the result (acc), otherwise the result is returned from the reducer untouched. Note there is no short-circuiting - all values are processed, either being ignored or added to the result.

const isEven = x => x % 2 === 0

const numbers = [
  1,
  2,
  3,
  4,
  5,
  6,
  7
]

const predicateIterator = (predicate, iterator) => (acc, value) =>
  predicate(value) ? iterator(acc, value) : acc;

const reduceIf = curry((predicate, iterator, seed, value) => 
  reduce(predicateIterator(predicate, iterator), seed, value));

const reduceIfEven = reduceIf(isEven, add, 0);

reduceIfEven(numbers); // 12 (2 + 4 + 6)

How can I create a comparable function using transduce?

My initial attempt hit a wall because I need the first function to receive both the result and the value which map doesn't.

const transducer = compose(filter(isEven), ????(add));
const reduceIfEven = transduce(transducer, R.flip(R.append), []);

Note: this is an academic exercise. I'm just interested in how it can be done, not whether it should be done this way.


Solution

  • Using the isOdd example in the transduce() documentation, you can filter() all even, and add() them with the accumulator.

    const { transduce, add, filter } = R
    
    const numbers = [1,2,3,4,5,6,7]
    
    const isEven = x => x % 2 === 0
    
    const sumIfEven = transduce(filter(isEven), add, 0)
    
    console.log(sumIfEven(numbers))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>