Created
March 28, 2016 19:35
-
-
Save dypsilon/f96e90adc7cc19d6af1d 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
| function arrayReduce(xf, init, array){ | |
| var value = init; | |
| var idx = 0; | |
| var length = array.length; | |
| for(; idx < length; idx++){ | |
| value = xf.step(value, array[idx]); | |
| if(isReduced(value)){ | |
| value = deref(value); | |
| break; | |
| } | |
| } | |
| return xf.result(value); | |
| } | |
| function reduce(xf, init, input){ | |
| if(typeof xf === 'function'){ | |
| xf = wrap(xf); | |
| } | |
| return arrayReduce(xf, init, input); | |
| } | |
| function reduced(value){ | |
| return { | |
| value: value, | |
| __transducers_reduced__: true | |
| } | |
| } | |
| function isReduced(value){ | |
| return value && value.__transducers_reduced__; | |
| } | |
| function deref(reducedValue){ | |
| return reducedValue.value; | |
| } | |
| function append(value, item){ | |
| value.push(item); | |
| return value; | |
| } | |
| function compose2(fn1, fn2){ | |
| return function(item){ | |
| return fn1(fn2(item)); | |
| } | |
| } | |
| function isOdd(num){ | |
| return num % 2 === 1; | |
| } | |
| function isEqual(y){ | |
| return function(x){ | |
| return x === y; | |
| } | |
| } | |
| function not(predicate){ | |
| return function(x){ | |
| return !predicate(x); | |
| } | |
| } | |
| function compose(/*fns*/){ | |
| var fns = arguments; | |
| return function(xf){ | |
| var i = fns.length - 1; | |
| for(; i >= 0; i--){ | |
| xf = fns[i](xf); | |
| } | |
| return xf; | |
| } | |
| } | |
| 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; | |
| } | |
| } | |
| } | |
| // returns a trancducer which is capped to n items | |
| function take(n){ | |
| return function(xf){ | |
| var left = n; | |
| return { | |
| init: function(){ | |
| return xf.init(); | |
| }, | |
| step: function(value, item){ | |
| value = xf.step(value, item); | |
| if(--left <= 0){ | |
| // we are done, so signal reduced | |
| value = reduced(value); | |
| } | |
| return value; | |
| }, | |
| result: function(value){ | |
| return xf.result(value); | |
| } | |
| } | |
| } | |
| } | |
| 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 | |
| var 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); | |
| } | |
| function map(f){ | |
| return function(xf){ | |
| return { | |
| init: function(){ | |
| return xf.init(); | |
| }, | |
| step: function(value, item){ | |
| var mapped = f(item); | |
| return xf.step(value, mapped); | |
| }, | |
| result: function(value){ | |
| return xf.result(value); | |
| } | |
| } | |
| } | |
| } | |
| function filter(predicate){ | |
| return function(xf){ | |
| return { | |
| init: function(){ | |
| return xf.init(); | |
| }, | |
| step: function(value, item){ | |
| var allow = predicate(item); | |
| if(allow){ | |
| value = xf.step(value, item); | |
| } | |
| return value; | |
| }, | |
| result: function(value){ | |
| return xf.result(value); | |
| } | |
| } | |
| } | |
| } | |
| function plus1(input){ | |
| return input + 1; | |
| } | |
| function plus2(input){ | |
| return input + 2; | |
| } | |
| var transducerPlus1 = function(xf){ | |
| return { | |
| init: function(){ | |
| return xf.init(); | |
| }, | |
| step: function(result, item){ | |
| return xf.step(result, plus1(item)); | |
| }, | |
| result: function(result){ | |
| return xf.result(result); | |
| } | |
| } | |
| } | |
| var transducer = filter(isOdd); | |
| var stepper = append; | |
| var init = []; | |
| var input = [1,2,3,4,5]; | |
| var output = transduce(transducer, stepper, init, input); | |
| // [1,3,5] | |
| console.log(output); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment