Let's say we have following semigroups:
// Total: Sum up all the number const Total = (x) => ({ x, concat(o) { return Total(o.x + x); }, fold() { return x; }, toString() { return `Total(${x})`; }, }); Total.empty = () => Total(0); const Max = (x) => ({ x, concat(o) { return Max(Math.max(x, o.x)); }, fold() { return x; }, }); Max.empty = () => Max(Number.MIN_VALUE);
We want to define a 'List' type which has 'foldMap' function:
const List = (x) => ({ x, foldMap(type, _empty) { const empty = _empty ? _empty : type.empty(); if (!empty) throw new Error(`foldMap expect an empty as second value`); return x .map(type) .reduce((acc, curr) => { return acc.concat(curr); }, empty) .fold(); }, });
Then we can use it:
console.log(List([1, 2, 3]).foldMap(Total)); // 6 console.log(List([1, 2, 3]).foldMap(Total, Total.empty())); console.log(List([1, 2, 3]).foldMap(Max)); // 3 console.log(List([1, 2, 3]).foldMap(Max, Max.empty()));