Last active
January 14, 2020 17:33
-
-
Save PartyLich/fbda0f35432710e1b4113f33c9b7039c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
const compose = (...fns) => (val) => fns.reduceRight((x, fn) => fn(x), val); | |
const sum = (result, item) => result + item; | |
const mult = (a, b) => a * b; | |
function wrap(xf){ | |
return { | |
// 1. We require init as arg, so do not need here | |
init: function(){ | |
throw new Error('init not supported'); | |
}, | |
// 2. Input one item at a time, passing | |
// each result to next iteration | |
step: xf, | |
// 3. Output last computed result | |
result: function(result){ | |
return result; | |
} | |
} | |
} | |
/** | |
* @param xf A transformer or reducing function to be wrapped as a transformer | |
* @param init An initial value (like []) | |
* @param input An input source (like an array to reduce) | |
*/ | |
function reduce(xf, init, input) { | |
if(typeof xf === 'function'){ | |
// make sure we have a transformer | |
xf = wrap(xf); | |
} | |
const result = input.reduce(xf.step, init); | |
return xf.result(result); | |
} | |
function append(result, item) { | |
result.push(item); | |
return result; | |
} | |
const plus1 = (item) => item + 1; | |
/** | |
* transducer A transducer that defines the transformation | |
* stepper A stepper function or transformer (like append) | |
* init An initial value for the the stepper function (like []) | |
* input The input source (e.g. an array to transform) | |
*/ | |
function transduce(transducer, stepper, init, input){ | |
if (typeof stepper === 'function') { | |
// make sure we have a transformer for stepping | |
stepper = wrap(stepper); | |
} | |
// pass in stepper to create transformer | |
const xf = transducer(stepper); | |
// xf is now a transformer | |
// we now can use reduce defined above to | |
// iterate and transform input | |
return reduce(xf, init, input); | |
} | |
// define the mapping transducer | |
/** | |
* @param {function} fn a mapping function | |
* @param {object} xf transformer | |
*/ | |
const map = (fn) => (xf) => ({ | |
init() { | |
return xf.init(); | |
}, | |
step(result, item) { | |
const mapped = fn(item); | |
return xf.step(result, mapped); | |
}, | |
result(result) { | |
return xf.result(result); | |
} | |
}); | |
const plus2 = (input) => input + 2; | |
const transducerPlus2 = map(plus2); | |
// filter transducer | |
const filter = (predicate) => (xf) => ({ | |
init() { | |
return xf.init(); | |
}, | |
step(value, item) { | |
const allow = predicate(item); | |
return allow | |
? xf.step(value, item) | |
: value; | |
}, | |
result(result) { | |
return xf.result(result); | |
} | |
}); | |
const isOdd = (num) => num % 2 === 1; | |
{ | |
var transducer = filter(isOdd); | |
var stepper = append; | |
var init = []; | |
var input = [1,2,3,4,5]; | |
var output = transduce(transducer, stepper, init, input); | |
console.log(output); | |
} | |
const isEqual = (a) => (b) => a === b; | |
const not = (predicate) => (val) => !predicate(val); | |
// remove transducer | |
const remove = (predicate) => filter(not(predicate)); | |
{ | |
var transducer = compose( | |
filter(isOdd), // [1,3,5] | |
map(plus1), // [2,4,6] | |
remove(isEqual(4))); // [2,6] | |
var stepper = append; | |
var init = []; | |
var input = [1,2,3,4,5]; | |
var output = transduce(transducer, stepper, init, input); | |
console.log(output); | |
} | |
// stateful transformer using a stateless transducer | |
// skip n items at the beginning of the iteration | |
const drop = (n) => (xf) => { | |
let left = n; | |
return { | |
init() { | |
return xf.init(); | |
}, | |
step(value, item) { | |
if (left <= 0) { | |
return xf.step(value, item); | |
} | |
left--; | |
return value; | |
}, | |
result(result) { | |
return xf.result(result); | |
} | |
} | |
} | |
{ | |
var transducer = drop(2); | |
var stepper = append; | |
var init = []; | |
var input = [1,2,3,4,5]; | |
var output = transduce(transducer, stepper, init, input); | |
console.log(output); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment