Skip to content

Instantly share code, notes, and snippets.

@dypsilon
Created March 28, 2016 19:35
Show Gist options
  • Select an option

  • Save dypsilon/f96e90adc7cc19d6af1d to your computer and use it in GitHub Desktop.

Select an option

Save dypsilon/f96e90adc7cc19d6af1d to your computer and use it in GitHub Desktop.
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