diff options
author | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2024-02-13 20:00:02 -0700 |
---|---|---|
committer | Elizabeth Hunt <elizabeth.hunt@simponic.xyz> | 2024-02-13 20:00:02 -0700 |
commit | 0c476e92e1807928ffb30864126076ef4c6a0821 (patch) | |
tree | a4992161ce4b6203edffb5d78533e9c73e61e6f1 /examples/sum_of_even_squares.ts | |
parent | 512c245466fad78106a046c1ea6233acdcc3e4de (diff) | |
download | compiling-the-lambda-calculus-main.tar.gz compiling-the-lambda-calculus-main.zip |
Diffstat (limited to 'examples/sum_of_even_squares.ts')
-rw-r--r-- | examples/sum_of_even_squares.ts | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/examples/sum_of_even_squares.ts b/examples/sum_of_even_squares.ts new file mode 100644 index 0000000..b4c1aad --- /dev/null +++ b/examples/sum_of_even_squares.ts @@ -0,0 +1,151 @@ +const isEven = (n: number) => { + let even = true; // 0 is even + + for (let i = 1; i <= n; i++) { + even = !even; + } + + return even; +}; + +const sumOfEvenSquares = (upTo: number) => { + let sum = 0; + + for (let i = 1; i <= upTo; i++) { + if (isEven(i)) { + sum += i * i; + } + } + + return sum; +}; + +/** + * functional + */ + +const isEvenHelper = (curr: number, max: number, previous = false) => { + if (curr === max) { + return !previous; + } + + return isEvenHelper(curr + 1, max, !previous); +}; + +const isEvenFn = (n: number) => { + return isEvenHelper(0, n); +}; + +const map = ( + transform: (x: number, ind: number) => number, + list: number[], + index = 0, +) => { + if (list.length === 0) { + return []; + } + const [head, ...tail] = list; + const transformed = transform(head, index); + + return [transformed].concat(map(transform, tail, index + 1)); +}; + +const filter = (predicate: (x: number) => boolean, list: number[]) => { + if (list.length === 0) { + return []; + } + + const [head, ...tail] = list; + if (predicate(head)) { + return [head].concat(filter(predicate, tail)); + } + return filter(predicate, tail); +}; + +const reduce = ( + accumulation: (x: number, accumulator: number) => number, + accumulator: number, + list: number[], +) => { + if (list.length === 0) { + return accumulator; + } + + const [head, ...tail] = list; + const newAccumulator = accumulation(head, accumulator); + return reduce(accumulation, newAccumulator, tail); +}; + +const curriedReduce = ( + accumulation: (x: number, accumulator: number) => number, +) => { + return (accumulator: number) => { + const reduce = (list: number[]) => { + if (list.length === 0) { + return accumulator; + } + + const [head, ...tail] = list; + const newAccumulator = accumulation(head, accumulator); + + return curriedReduce(accumulation)(newAccumulator)(tail); + }; + + return reduce; + }; +}; + +const sum = curriedReduce((x, acc) => x + acc)(0); + +const sumOfEvenSquaresFn = (upTo: number) => { + const numbersUpTo = Array(upTo + 1) + .fill(0) + .map((_, i) => i); + const squares = numbersUpTo.filter((x) => isEvenFn(x)).map((x) => x * x); + + return sum(squares); +}; + +/** + * test + */ + +const assert = (predicate: () => boolean, message: string) => { + const start = performance.now(); + + console.log(message + "..."); + const result = predicate(); + + const runtimeFmt = ` in ${(performance.now() - start).toFixed(5)}ms`; + if (result) { + console.log(" ... PASSED" + runtimeFmt); + return; + } + + console.error(" ... FAILED" + runtimeFmt); + throw new Error("predicate failed for test: " + message); +}; + +/* + Σ(2i)^2 = 4 * Σ(i)^2 = 4 * (n * (n + 1) * (2 * n + 1)) / 6 + */ +const constantTimeMathMagic = (x: number) => { + const n = Math.floor(x / 2); // even numbers + return (4 * (n * (n + 1) * (2 * n + 1))) / 6; +}; + +const test = (sumEvenSquarer: (x: number) => number) => { + assert(() => sumEvenSquarer(5) === 2 ** 2 + 4 ** 2, "up to 5"); + assert( + () => sumEvenSquarer(10) === 2 ** 2 + 4 ** 2 + 6 ** 2 + 8 ** 2 + 10 ** 2, + "up to 10", + ); + + //assert( + // () => sumEvenSquarer(75_000) === constantTimeMathMagic(75_000), + // "up to 75,000", + //); +}; + +test(sumOfEvenSquares); +test(sumOfEvenSquaresFn); |