Skip to content

Instantly share code, notes, and snippets.

@odyss009
Created March 1, 2017 15:56
Show Gist options
  • Save odyss009/05a9e5f0773f2c09accacd1083e1de24 to your computer and use it in GitHub Desktop.
Save odyss009/05a9e5f0773f2c09accacd1083e1de24 to your computer and use it in GitHub Desktop.

Revisions

  1. odyss009 created this gist Mar 1, 2017.
    52 changes: 52 additions & 0 deletions function.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,52 @@
    // Count the iterations
    let count = 0;

    const isMultipleOf3Or5 = n => (n % 3 === 0 || n % 5 === 0);

    // Reducer functions can be composed if we abstract the differences.
    // The filter's predicate function will need to be abstracted
    // and curried in for function composition:
    const filterReducer = predicate => reducer => (
    acc, item
    ) => predicate(item) ? reducer(acc, item) : acc;

    // The mapping function needs to be abstracted and curried in
    // to make a map reducer composable:
    const mapReducer = mapper => reducer => (
    acc, item
    ) => {
    count++;
    return reducer(acc, mapper(item));
    };

    // A shared reducing function abstracts how individual values
    // get accumulated together:
    const arrReducer = (acc = [], item) => acc.concat([item]);

    const double = x => x * 2;

    // Generic function composition
    const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);

    // Compose curried reducers, passing in the shared
    // reducing function. The returned reducer can be directly used
    // by any standard reduce() utility:
    const composeReducers = reducingFn => (...fns) => compose(...fns)(reducingFn);

    // Create a transducer: A function which can feed values
    // through multiple reducers without traversing the collection
    // more than once. If you filter the collection in a previous
    // step, the total work will not exceed the size of the filtered
    // set.
    const transducer = composeReducers(arrReducer)(
    filterReducer(isMultipleOf3Or5),
    mapReducer(x => x + 1),
    );

    // Usage
    const range = (start, end) => Array.from({ length: end - start + 1 }, (x, i) => i + start);

    const doubled = range(1,9)
    .reduce(transducer, []);

    console.log(doubled, count);