Skip to content

Instantly share code, notes, and snippets.

@abiodun0
Last active April 18, 2022 11:26
Show Gist options
  • Save abiodun0/7f9c3ce22e06e23381e5918f4b000860 to your computer and use it in GitHub Desktop.
Save abiodun0/7f9c3ce22e06e23381e5918f4b000860 to your computer and use it in GitHub Desktop.
Church Encoding / Peano Numbers
const zero = () => false;
const isZero = (a) => a == zero();
const succ = (a) => () => a;
const pred = (a) => a();
const converToPeano = (n, acc = zero()) => n === 0 ? acc : converToPeano(n - 1, succ(acc))
const _0 = zero(),
_1 = succ(_0),
_2 = succ(_1),
_3 = succ(_2),
_4 = succ(_3),
_5 = succ(_4);
const five = converToPeano(5)
const four = pred(five)
// Regular Arithmentic with just functions
const add = (a, b) => isZero(a) ? b : add(pred(a), succ(b));
const sub = (a, b) => isZero(a) || isZero(b) ? a : sub(pred(a), pred(b));
const mul = (a, b) => isZero(a) ? zero() : add(mul(pred(a), b), b);
const div = (a, b) => isZero(a) ? zero() : succ(div(sub(a, b), b));
// Equality with just functions
const equal = (a, b) => isZero(a) ? isZero(b) : isZero(b) ? false : equal(pred(a), pred(b));
const less = (a, b) => isZero(a) ? !isZero(b) : isZero(b) ? false : less(pred(a), pred(b));
const greater = (a, b) => ! (equal(a, b) || less(a, b));
// For debugging purposes
const toNumber = (a) => isZero(a) ? 0 : 1 + toNumber(pred(a));
console.log(toNumber(five), 'are we correct?')
console.log(toNumber(add(_1, _2))); // 10
console.log(toNumber(whatAreyou)); // 10
console.log(toNumber(div(add(_2, _2), _2))); // 2
console.log(equal(add(_1, _1), div(_4, _2))); // true
console.log(less(div(_4, _2), _4)); // true
console.log(greater(mul(_4, _2), _5)); // true
const zero = Symbol()
const isZero = a => a === zero
const succ = a => () => a
const pred = a => a()
// convienince for converting
const toPeano = (n, acc=zero) => {
if(n === 0) {
return acc
}
return toPeano(n - 1, succ(acc))
}
// convienince for debugging used below
const toNumber = (peano) => {
if (peano === zero) {
return 0;
}
return 1 + toNumber(pred(peano))
}
const _0 = zero,
_1 = succ(zero),
_2 = succ(_1),
_3 = succ(_2),
_4 = succ(_3),
_5 = succ(_4),
_6 = succ(_5),
_7 = succ(_6),
_8 = succ(_7),
_9 = succ(_8);
// Arithmentic
const add = (a, b) => {
if(a === zero) {
return b;
}
if (b === zero) {
return a;
}
return add(pred(a), succ(b))
}
const sub = (a, b) => {
if (a === zero) {
return zero;
}
if (b === zero) {
return a;
}
return sub(pred(a), pred(b))
}
const multiply = (a, b) => {
if(a === zero || b === zero ) {
return zero;
}
return add(multiply(pred(a), b), b)
}
const div = (a, b) => {
if (a === zero) {
return zero
}
return succ(div(sub(a, b), b))
}
// Equality
const equal = (a, b) => {
if(a === zero && b === zero) {
return true
}
if(a === zero && b !== zero || a !== zero && b === zero) {
return false
}
return equal(pred(a), pred(b))
}
const less = (a, b) => {
if(a === zero && b !== zero) {
return true
}
if(a !== zero && b === zero || a === 0 && b === 0) {
return false
}
return less(pred(a), pred(b))
}
const greater = (a, b) => {
if(a !== zero && b === zero) {
return true
}
if(a === zero && b !== zero || a === 0 && b === 0) {
return false
}
return greater(pred(a), pred(b))
}
// Examples
console.log(toNumber(add(_5, _5)), 'is it 10?')
console.log(toNumber(sub(_8, _5)), 'is it 3?')
console.log(toNumber(multiply(_8, _2)), 'is it 16?')
console.log(toNumber(multiply(_9, _9)), 'is it 81?')
console.log(toNumber(multiply(_8, _0)), 'is it 0?')
console.log(toNumber(div(_8, _4)), 'is it 2?')
console.log((equal(_8, _8)), 'is it true')
console.log((equal(_8, _7)), 'is it false')
console.log((less(_8, _7)), 'is it false')
console.log((less(_4, _5)), 'is it false')
console.log((greater(_8, _7)), 'is it true')
console.log((greater(_7, _9)), 'is it false')
const zero = Symbol()
const isZero = a => a === zero
const succ = a => () => a
const pred = a => a()
// convienince for converting
const toPeano = (n, acc=zero) => {
if(n === 0) {
return acc
}
return toPeano(n - 1, succ(acc))
}
// convienince for debugging used below
const toNumber = (peano) => {
if (peano === zero) {
return 0;
}
return 1 + toNumber(pred(peano))
}
const _0 = zero,
_1 = succ(zero),
_2 = succ(_1),
_3 = succ(_2),
_4 = succ(_3),
_5 = succ(_4),
_6 = succ(_5),
_7 = succ(_6),
_8 = succ(_7),
_9 = succ(_8);
// Arithmentic
const add = (a, b) => {
if(isZero(a)) {
return b;
}
if (isZero(b)) {
return a;
}
return add(succ(a), pred(b))
}
const sub = (a, b) => {
if (isZero(a)) {
return zero;
}
if (isZero(b)) {
return a;
}
return sub(pred(a), pred(b))
}
const multiply = (a, b) => {
if(isZero(a) ||isZero(b) ) {
return zero;
}
return add(b, multiply(pred(a), b))
}
const div = (a, b) => {
if (isZero(a)) {
return zero
}
return succ(div(sub(a, b), b))
}
const exp = (a, b) => {
if(isZero(a)) {
return zero
}
if(isZero(b)) {
return succ(zero)
}
return multiply(exp(a, pred(b)), a)
}
// for a sample
// exp(4, 3)
// multiply(exp(4, 2), 4)
// multiply(multiply(exp(4, 1), 4), 4)
// multiply(multiply(multiply(exp(4, 0), 4), 4), 4)
// multiply(multiply(multiply(1, 4), 4), 4)
const log = (a, b) => {
if(isZero(b())) {
return zero
}
return succ(log(a, div(b, a)))
}
// Equality
const equal = (a, b) => {
if(isZero(a) && isZero(b)) {
return true
}
if(isZero(a) && !(isZero(b)) || !isZero(a) && isZero(b)) {
return false
}
return equal(pred(a), pred(b))
}
const less = (a, b) => {
if(isZero(a) && !isZero(b)) {
return true
}
if(!isZero(a) && isZero(b) || isZero(a) && isZero(b)) {
return false
}
return less(pred(a), pred(b))
}
const greater = (a, b) => {
if(!isZero(a) && isZero(b)) {
return true
}
if(isZero(a) && !isZero(b) || isZero(a) && isZero(b)) {
return false
}
return greater(pred(a), pred(b))
}
// Examples
console.log(toNumber(add(_5, _5)), 'is it 10?')
console.log(toNumber(sub(_8, _5)), 'is it 3?')
console.log(toNumber(multiply(_8, _2)), 'is it 16?')
console.log(toNumber(multiply(_9, _9)), 'is it 81?')
console.log(toNumber(multiply(_8, _0)), 'is it 0?')
console.log(toNumber(multiply(_8, _0)), 'is it 0?')
console.log(toNumber(exp(_5, _2)), 'is it 25? exponential')
console.log(toNumber(exp(toPeano(10), _2)), 'is it 100? exponential')
console.log(toNumber(div(_8, _4)), 'is it 2?')
console.log((equal(_8, _8)), 'is it true')
console.log((equal(_8, _7)), 'is it false')
console.log((less(_8, _7)), 'is it false less')
console.log((less(_4, _5)), 'is it true less')
console.log((greater(_8, _7)), 'is it true')
console.log((greater(_7, _9)), 'is it false')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment