Skip to content

Instantly share code, notes, and snippets.

@neilgall
Created January 16, 2017 22:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neilgall/caa5e32c56b784e75b54bffa3a618e79 to your computer and use it in GitHub Desktop.
Save neilgall/caa5e32c56b784e75b54bffa3a618e79 to your computer and use it in GitHub Desktop.
Lambda Calculus Fizzbuzz (in Javascript)
// Integers
const ZERO = p => a => a
const INCREMENT = n => p => x => p(n(p)(x))
const ONE = INCREMENT(ZERO)
const TWO = INCREMENT(ONE)
const THREE = INCREMENT(TWO)
const FOUR = INCREMENT(THREE)
const FIVE = INCREMENT(FOUR)
// Booleans
const TRUE = x => y => x
const FALSE = x => y => y
const IF = b => b
// Pairs
const PAIR = x => y => f => f(x)(y)
const LEFT = p => p(x => y => x)
const RIGHT = p => p(x => y => y)
// Integer operations
const SLIDE = p => PAIR(RIGHT(p))(INCREMENT(RIGHT(p)))
const DECREMENT = n => LEFT(n(SLIDE)(PAIR(ZERO)(ZERO)))
const ADD = m => n => n(INCREMENT)(m)
const SUBTRACT = m => n => n(DECREMENT)(m)
const MULTIPLY = m => n => n(ADD(m))(ZERO)
const POWER = m => n => n(MULTIPLY(m))(ONE)
// Integer comparisons
const IS_ZERO = n => n(x => FALSE)(TRUE)
const LESS_OR_EQUAL = m => n => IS_ZERO(SUBTRACT(m)(n))
// Combinators
const Y_COMBINATOR = f => (x => f(x(x)))(x => f(x(x)))
const Z_COMBINATOR = f => (x => f(y => x(x)(y)))(x => f(y => x(x)(y)))
const DIV = Z_COMBINATOR(f => m => n =>
IF(LESS_OR_EQUAL(n)(m))
(x => INCREMENT(f(SUBTRACT(m)(n))(n))(x))
(ZERO)
)
const MOD = Z_COMBINATOR(f => m => n =>
IF(LESS_OR_EQUAL(n)(m))
(x => f(SUBTRACT(m)(n))(n)(x))
(m)
)
// Lists
const EMPTY = PAIR(TRUE)(TRUE)
const IS_EMPTY = LEFT
const UNSHIFT = xs => x => PAIR(FALSE)(PAIR(x)(xs))
const FIRST = xs => LEFT(RIGHT(xs))
const REST = xs => RIGHT(RIGHT(xs))
// Range
const RANGE = Z_COMBINATOR(f => m => n =>
IF(LESS_OR_EQUAL(m)(n))
(r => UNSHIFT(f(INCREMENT(m))(n))(m)(r))
(EMPTY)
)
// List operations
const FOLD = Z_COMBINATOR(f => xs => x => g =>
IF(IS_EMPTY(xs))
(x)
(y => g(f(REST(xs))(x)(g))(FIRST(xs))(y))
)
const PUSH = xs => x => FOLD(xs)(UNSHIFT(EMPTY)(x))(UNSHIFT)
const MAP = xs => f => FOLD(xs)(EMPTY)(ys => x => UNSHIFT(ys)(f(x)))
// Strings
const B = MULTIPLY(TWO)(FIVE)
const F = INCREMENT(B)
const I = INCREMENT(F)
const U = INCREMENT(I)
const Z = INCREMENT(U)
const FIZZ = UNSHIFT(UNSHIFT(UNSHIFT(UNSHIFT(EMPTY)(Z))(Z))(I))(F)
const BUZZ = UNSHIFT(UNSHIFT(UNSHIFT(UNSHIFT(EMPTY)(Z))(Z))(U))(B)
const FIZZBUZZ = UNSHIFT(UNSHIFT(UNSHIFT(UNSHIFT(BUZZ)(Z))(Z))(I))(F)
// Integer to string
const NINE = MULTIPLY(THREE)(THREE)
const TEN = INCREMENT(NINE)
const TO_DIGITS = Z_COMBINATOR(f => n =>
PUSH(
IF(LESS_OR_EQUAL(n)(NINE))
(EMPTY)
(x => f(DIV(n)(TEN))(x))
)(MOD(n)(TEN))
)
// FIZZBUZZ
const HUNDRED = MULTIPLY(TEN)(TEN)
const FIFTEEN = ADD(TEN)(FIVE)
const DO_FIZZBUZZ = n =>
IF(IS_ZERO(MOD(n)(FIFTEEN)))
(FIZZBUZZ)
(IF(IS_ZERO(MOD(n)(FIVE)))
(FIZZ)
(IF(IS_ZERO(MOD(n)(THREE)))
(BUZZ)
(TO_DIGITS(n))))
const SOLUTION = MAP(RANGE(ONE)(HUNDRED))(DO_FIZZBUZZ)
// Convenience output
const to_integer = n => n(x => x+1)(0)
const to_boolean = b => b(true)(false)
const to_array = xs => {
var array = []
while (!to_boolean(IS_EMPTY(xs))) {
array.push(FIRST(xs))
xs = REST(xs)
}
return array
}
const to_char = c => "0123456789BFiuz"[to_integer(c)]
const to_string = s => to_array(s).map(to_char).join("")
to_array(SOLUTION).forEach(p => console.log(to_string(p)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment