Created
June 3, 2021 09:38
-
-
Save andrewjpritchard/efe47aa4b9a518b76444b1c710fe2b5f to your computer and use it in GitHub Desktop.
FizzBuzz using nothing but closures and variable declarations
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
(( | |
log: (str: string | number) => void, | |
join: (a: string, b: string) => string, | |
fizz: string, | |
buzz: string, | |
zeroNative: number, | |
succNative: (n: number) => number, | |
) => { | |
type Boolean = <T>( | |
$true: () => T, | |
$false: () => T, | |
) => T; | |
// use $true and $false since true and false are reserved | |
const True: Boolean = ($true, _$false) => $true(); | |
const False: Boolean = (_$true, $false) => $false(); | |
const not = (predicate: Boolean): Boolean => predicate( | |
() => False, | |
() => True, | |
); | |
type Number = <T>( | |
zero: () => T, | |
succ: (n: Number) => T, | |
) => T; | |
const Z: Number = (zero, _succ) => zero(); | |
const S = (n: Number): Number => (_zero, succ) => succ(n); | |
const add = (a: Number, b: Number): Number => a( | |
() => b, | |
(n) => add(n, S(b)), | |
); | |
const equals = (a: Number, b: Number): Boolean => a( | |
() => b( | |
() => True, | |
() => False, | |
), | |
(predA) => b( | |
() => False, | |
(predB) => equals(predA, predB), | |
) | |
); | |
const gt = (a: Number, b: Number): Boolean => a( | |
() => False, | |
(predA) => b( | |
() => True, | |
(predB) => gt(predA, predB), | |
) | |
); | |
const leq = (a: Number, b: Number): Boolean => not(gt(a, b)); | |
const toNative = (n: Number): number => n( | |
() => zeroNative, | |
(n) => succNative(toNative(n)), | |
) | |
const n1 = S(Z); | |
const n2 = add(n1, n1); | |
const n4 = add(n2, n2); | |
const n8 = add(n4, n4); | |
const n16 = add(n8, n8); | |
const n32 = add(n16, n16); | |
const n64 = add(n32, n32); | |
// use right associativity for efficiency, rightmost number should be the largest | |
const n100 = add(n4, add(n32, n64)); | |
const fizzBuzz = (n: Number, fizzCount: Number, buzzCount: Number) => | |
leq(n100, n)( | |
() => {}, | |
() => { | |
const nextFizz = gt(fizzCount, n2)( | |
() => Z, | |
() => S(fizzCount), | |
) | |
const nextBuzz = gt(buzzCount, n4)( | |
() => Z, | |
() => S(buzzCount), | |
); | |
const line = equals(fizzCount, Z)( | |
() => equals(buzzCount, Z)( | |
() => join(fizz, buzz), | |
() => fizz | |
), | |
() => equals(buzzCount, Z)( | |
() => buzz, | |
(): number | string => toNative(n) | |
) | |
); | |
log(line); | |
fizzBuzz(S(n), nextFizz, nextBuzz); | |
} | |
) | |
fizzBuzz(n1, n1, n1); | |
})(console.log, (a, b) => a + b, "Fizz", "Buzz", 0, (n) => ++n) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment