Contrived example of transducers in action
// Common Utilities | |
function compose(...fns) { | |
const apply = (arg, fn) => fn(arg); | |
return (initial) => fns.reduceRight(apply, initial); | |
} | |
function curry(arity, fn, ...rest) { | |
if(arity <= rest.length) { | |
return fn(...rest); | |
} | |
return curry.bind(null, arity, fn, ...rest); | |
} | |
// Transducers stuff | |
const Combine = { | |
push: (state, value) => (state.push(value), state), | |
add: (state, value) => state.add(value), | |
concat: (state, value) => state.concat(value) | |
}; | |
function reduce(reducer, initial, collection) { | |
let state = initial; | |
for(let value of collection) { | |
state = reducer(state, value); | |
} | |
return state; | |
} | |
function transduce(combine, initial, transducer, collection) { | |
return reduce(transducer(combine), initial, collection); | |
} | |
const Into = { | |
array: curry(2, function(transducer, collection) { | |
return transduce(Combine.push, [], transducer, collection); | |
}), | |
string: curry(2, function(transducer, collection) { | |
return transduce(Combine.concat, "", transducer, collection) | |
}), | |
set: curry(2, function(transducer, collection) { | |
return transduce(Combine.add, new Set(), transducer, collection); | |
}), | |
}; | |
function filter(predicate, next) { | |
if(arguments.length === 1) { | |
return (_next) => filter(predicate, _next); | |
} | |
return function reducer(state, value) { | |
if(predicate(value)) { | |
return next(state, value); | |
} | |
return state; | |
}; | |
} | |
function map(transform, next) { | |
if(arguments.length === 1) { | |
return (_next) => map(transform, _next); | |
} | |
return function reducer(state, value) { | |
return next(state, transform(value)); | |
}; | |
} | |
// Contrived example | |
const is_even = number => number % 2 === 0; | |
const is_positive = number => number > 0; | |
const add_message = number => `The number is: ${number}`; | |
const transducer = compose( | |
filter(is_positive), | |
filter(is_even), | |
map(add_message) | |
); | |
const array = [-2, -1, 0, 1, 2, 3]; | |
const set = new Set([-2, -1, 0, 1, 2, 3]); | |
const to_string = Into.string(transducer); | |
console.log( | |
'\nTransducer with Array.reduce\n', | |
array.reduce(transducer(Combine.push), []), | |
'\n' | |
); | |
console.log( | |
'Transducer with custom reduce (on Array)\n', | |
Into.array(transducer, array), | |
'\n' | |
); | |
console.log( | |
'Transducer with custom reduce (on Set)\n', | |
Into.set(transducer, set), | |
'\n' | |
); | |
console.log( | |
'Transducer with custom reduce (from Array to String)\n', | |
Into.string(transducer, array), | |
'\n' | |
); | |
console.log( | |
'Transducer with custom reduce (from Set to String)\n', | |
to_string(set), | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment