Created
January 16, 2017 22:24
-
-
Save neilgall/caa5e32c56b784e75b54bffa3a618e79 to your computer and use it in GitHub Desktop.
Lambda Calculus Fizzbuzz (in Javascript)
This file contains hidden or 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
// 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