Skip to content

Instantly share code, notes, and snippets.

@kevinwucodes
Last active October 11, 2017 00:28
Show Gist options
  • Save kevinwucodes/b3a2d718d9489abedb287364db835cbc to your computer and use it in GitHub Desktop.
Save kevinwucodes/b3a2d718d9489abedb287364db835cbc to your computer and use it in GitHub Desktop.
All about transformers and reducers (aka transducers)

Eric Elliott had an interesting tweet that intrigued me: https://twitter.com/_ericelliott/status/912407669683609600?s=03

Here's what he posted:

const map = transform => reducer => ((acc, current) => reducer(acc, transform(current)))

const filter = predicate => reducer => (
  (acc, current) => predicate(current) ? reducer(acc, current) : acc
)

const isEven = filter(x => x % 2 === 0)
const double = map(n => n * 2)

In practice, we can apply this technique with something like this:

[1,2,3,4,5,6,7,8,9,10].reduce(double(
  (acc, current) => {
    // console.log('acc', acc);
    // console.log('current', current);
    acc.push(current);
    return acc;
  }
), [])
//[4, 8, 12, 16, 20]

But at first glance, I couldn't understand what was going on so I did some research and got some help from this article https://medium.com/@roman01la/understanding-transducers-in-javascript-3500d3bd9624

To help me "teach" myself, I deconstructed map and filter. When we deconstruct, we get something like this:

var mapSquaredReduce = (acc, current, index, ary) => {
  return (
    //think of this as an IIFE.  And the IIFE is getting arguments from the main (acc, current, index, ary)
    //and the IIFE is outputting/returning "acc2" which becomes the "acc" which is passed into the next "loop"
    (
      //this is the returned reducer
      (acc2, current2) => {
        console.log('acc2', acc2)
        console.log('current2', current2)
        acc2.push(current2)
        return acc2
      }
    )    
    (
      //these are the arguments passed to the returned reducer (acc2, current2)
      acc,
      (n => n * 2)(current)
    )
  )
}

Here's the filter transducer deconstructed

var filterEvenReduce = (acc, current, index, ary) => {
  if ((x => x % 2 === 0)(current)) {
    return (
      (
        //this is the returned reducer
        (acc2, current2) => {
          console.log('acc2', acc2)
          console.log('current2', current2)
          acc2.push(current2)
          return acc2
        }
      )
      (
        acc,
        current
      )
    )
  } else {
    return acc
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment