Skip to content

Instantly share code, notes, and snippets.

@lricoy
Created April 24, 2018 10:09
Show Gist options
  • Save lricoy/6d94c2d44625921a418fa28e522ec06e to your computer and use it in GitHub Desktop.
Save lricoy/6d94c2d44625921a418fa28e522ec06e to your computer and use it in GitHub Desktop.
Understanding fold
// ref: https://sidburn.github.io/blog/2017/03/19/understanding-fold
const eql = (expected, value) => {
if (expected !== value) {
throw new Error(`${expected} not equal to ${value}`);
}
};
eql('abc', 'abc');
eql(1, 1);
const empty = (xs: any[]) => xs.length === 0;
eql(empty([]), true);
eql(empty([1]), false);
const head = <T>(xs: T[]): T => xs[0];
eql(head([1, 2, 3]), 1);
eql(head([]), undefined);
const tail = <T>(xs: T[]): T[] => xs.slice(1);
eql(tail([1, 2, 3]).length, [2, 3].length);
eql(tail([1, 2]).length, [2].length);
const _fold = <A, B>(folder: (acc: B, val: A) => B, list: Array<A>, acc: B): B => {
if (empty(list)) {
return acc;
}
return _fold(folder, tail(list), folder(acc, head(list)));
};
const fold = <A, B>(
folder: (acc: B, val: A) => B,
initialValue: B,
list: Array<A>
): B => {
return _fold(folder, list, initialValue);
};
eql(fold((a, b) => a + b, 0, [1, 2, 3]), 6);
eql(fold((a, b) => a - b, 1, [2, 3]), -4);
const len = xs => fold((acc, val) => acc + 1, 0, xs);
eql(len([1, 2, 3]), 3);
eql(len(Array(100)), 100);
const rev = xs => fold((acc, val) => [val, ...acc], [], xs);
eql(head(rev([1, 2, 3])), 3);
eql(head(tail(rev([1, 2, 3]))), 2);
eql(head(tail(tail(rev([1, 2, 3])))), 1);
const map = (f, xs) => fold((acc, val) => [...acc, f(val)], [], xs);
eql(head(map(x => x + 10, [1, 2, 3])), 11);
eql(head(tail(map(x => x + 10, [1, 2, 3]))), 12);
eql(head(tail(tail(map(x => x + 10, [1, 2, 3])))), 13);
const filter = <A>(predicate: (x: A) => boolean, xs: A[]) =>
fold((acc, val) => (predicate(val) ? [...acc, val] : acc), [], xs);
eql(len(filter(x => x % 2 === 0, [1, 2, 3, 4])), 2);
eql(head(filter(x => x % 2 === 0, [1, 2, 3, 4])), 2);
eql(head(tail(filter(x => x % 2 === 0, [1, 2, 3, 4]))), 4);
const all = <A>(predicate: (x: A) => boolean, xs: A[]): boolean =>
fold((acc, val) => (!predicate(val) ? false : acc), true, xs);
eql(all(x => x === 1, [1,1,1,1]), true);
eql(all(x => x === 1, [1,1,1,2]), false);
eql(all(x => x % 2 === 0, [2,4,6,8,10]), true);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment