Skip to content

Instantly share code, notes, and snippets.

@andrewjpritchard
Created June 3, 2021 09:38
Show Gist options
  • Save andrewjpritchard/efe47aa4b9a518b76444b1c710fe2b5f to your computer and use it in GitHub Desktop.
Save andrewjpritchard/efe47aa4b9a518b76444b1c710fe2b5f to your computer and use it in GitHub Desktop.
FizzBuzz using nothing but closures and variable declarations
((
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