Skip to content

Instantly share code, notes, and snippets.

@anirudh-eka
anirudh-eka / exploring-fold-composition.js
Created June 13, 2022 16:59
Basically exploring 1. composing reducer functions 2. classic list fold, an early termination list fold, and a iterator fold.
// composeFolds :: [(a, x) -> (a | null)] -> ((a, x) -> (a | null))
//
// `composeFolds` composes reducer functions from left-to-right.
// For example, composeFolds(sum, take(10)) will first call `sum`,
// then `take(10)`. On each iteration of a fold, each reducer receieves
// the aggregate, and the new value (`x`), and returns a new aggregator
// that gets passed along to the next reducer, along with `x`.
//
function composeFolds(...fs) {
return fs.reduce((g, f) => (a, x) => {
// An implementation of a range construction with a lazily evaluated forEach
// Usage:
range(1,5).forEachLazy(console.log) //prints 1, 2, 3, 4, 5
range(1).forEachLazy(console.log) //prints 1, 2... forever
function range(from, to=Infinity) {
const gen = __range(from, to)
gen.forEachLazy = __forEachLazy(gen)
// Function Spread
// https://medium.com/@anirudheka/how-to-use-the-spread-operator-on-a-function-b7dd9d13752a?sk=b85ebf2107d618184ad4e44a2270835f
const spread = (...fns) =>
fns.reduce((a, f) => x => {
const v = f(x)
return v !== undefined ? v : a(x)
})
// usage
const mapping = mapLogic => reducer => (a, x) => {
const transformed = mapLogic(x);
return reducer(a, transformed)
}
const filtering = filterLogic => reducer => (a, x) => {
if(filterLogic(x)) {
return reducer(a, x)
} else {
return a;
const mapAdd1Transducer = reducer => (a, x) => {
const transformed = x + 1;
return reducer(a, transformed)
}
const filterGreaterThan2Transducer = reducer => (a, x) => {
if(x > 2) {
return reducer(a, x)
} else {
return a;
}
const mapAdd1Reducer = (a, x) => {
const transformed = x + 1;
return a.concat(transformed)
}
const filterGreaterThan2Transducer = reducer => (a, x) => {
if(x > 2) {
return reducer(a, x)
} else {
return a;
const filterGreaterThan2AndMapAdd1Reducer = (a, x) => {
if(x > 2) {
return mapAdd1Reducer(a, x)
} else {
return a;
}
}
[1, 2, 3].reduce(filterGreaterThan2AndMapAdd1Reducer, []);
const mapAdd1Reducer = (a, x) => {
const transformed = x + 1;
return a.concat(transformed)
}
const filterGreaterThan2Reducer = (a, x) => {
if(x > 2) {
return a.concat(x)
} else {
return a;
}
const jayZDetailsFn = (k) => jayZDetails[k];
const intermediateResult = mapFn(stringifyNumber, jayZDetailsFn);
//=> x => stringifyNumber(jayZDetailsFn(x))
const result = mapFn(addAgeSuffix,intermediateResult);
//=> x => addAgeSuffix(stringifyNumber(jayZDetailsFn(x)))
result('demeanorAge') //=> 'seventy eight years old';
const jayZDetails = { age: 48, demeanorAge: 78 };
const intermediateResult = mapObj(stringifyNumber, jayZDetails);
// => { age: 'forty eight', demeanorAge: 'seventy eight' }
const finalResult = mapObj(addAgeSuffix, intermediateResult));
// => { age: 'forty eight years old', demeanorAge: 'seventy eight years old' }
result['demeanorAge'] //=> 'seventy eight years old';