because brains
A simple but powerful language created in 1958 by Kurt Gödel
enum Nat {
case Z // 0
case S(Nat) // 1 + x
}
S(S(S(Z))) // 3
Z // 0
All natural numbers are of type `Nat`
Values
λ(x: τ)e
where `x` is some variable of some type `τ` and `e` is any expression.
// identity function on nats
λ(x: Nat)x
// function application
λ(x: Nat)x(Z) // => Z
Types
τ1 -> τ2
for any two types τ1 and τ2
// takes a Nat, returns a Nat
Nat -> Nat
// takes a (Nat -> Nat), returns a Nat
(Nat -> Nat) -> Nat
A Swift implementation:
func rec<U>(e: Int, e0: U, e1: (Int, U) -> U) -> U {
if e == 0 { // e = Z
return e0 // base case
} else { // e = S(x)
let x: Int = e - 1 // thus x can be any Nat
let y: U = rec(x, e0, e1) // result of recursion
return e1(x, y) // "recursive case"
}
}
rec e { Z => e0 | S(x) with y => e1 }
// e, e0, e1 are expressions
// x, y are variables
// this is fixed:
// rec _ { Z => _ | S(_) with _ => _ }
rec e { Z => e0 | S(x) with y => e1 }
// e, e0, e1 are expressions
// x, y are variables
// this is fixed:
// rec _ { Z => _ | S(_) with _ => _ }
Note that `y` is the result of the recursion
`e1` uses `y` but does not make the recursive call
Types
rec e { Z => e0 | S(x) with y => e1 }
// e: Nat
// e0: τ
// e1: τ
// x: Nat
// y: τ
plus := λ(a: Nat)λ(b: Nat) rec a { Z => b | S(x) with y => S(y) }
plus(0)(1) // =>
plus(Z)(S(Z)) // =>
rec Z { Z => S(Z) | S(x) with y => S(y) } // =>
S(Z) // =>
1
plus(1)(1) // =>
plus(S(Z))(S(Z)) // =>
rec S(Z) { Z => S(Z) | S(x) with y => S(y) } // =>
S(y) // where y = rec Z { Z => S(Z) | S(x) with y => S(y) } =>
S( rec Z { Z => S(Z) | S(x) with y => S(y) } ) // =>
S(S(Z)) // =>
2
plus := λ(a: Nat)λ(b: Nat) rec a { Z => b | S(x) with y => S(y) }
Take two numbers
Recurse on the first one
When it's zero
When it's not zero
0 + b = b // so return b
y = (a-1) + b
// we want "a + b"
(a-1) + b + 1 = y + 1 = S(y)
// so return S(y)