Skip to content

Instantly share code, notes, and snippets.

@VonHeikemen
Created December 26, 2020 19:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save VonHeikemen/a6b2b2e27ea999e87ebc30cf9c039295 to your computer and use it in GitHub Desktop.
Save VonHeikemen/a6b2b2e27ea999e87ebc30cf9c039295 to your computer and use it in GitHub Desktop.
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