Created
April 24, 2018 10:09
-
-
Save lricoy/6d94c2d44625921a418fa28e522ec06e to your computer and use it in GitHub Desktop.
Understanding fold
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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