λx. t
This could be expressed in a 'hypothetical conventional language' as:
fn(x) { t }
Lambda functions can only technically take one argument, but they can be curried to provide the same functionality:
λx.λy. t
This could be expressed in our hypothetical language as:
fn(x) { fn(y) { t } }
Booleans can be defined as the following functions:
tru = λt.λf. t
fls = λt.λf. f
These definitions may look strange at first, but they begin to make sense after we define some logical operators:
and = λb.λc. b c fls
and tru tru
= (λb.λc. b c fls) tru tru
-> (λc. tru c fls) tru
-> tru tru fls
= (λt.λf. t) tru fls
-> (λf. tru) fls
-> tru
and tru tru -> (λb.λc. b c fls) tru tru -> tru tru fls -> tru
and tru fls -> (λb.λc. b c fls) tru fls -> tru fls fls -> fls
and fls tru -> (λb.λc. b c fls) fls tru -> fls tru fls -> fls
and fls fls -> (λb.λc. b c fls) fls fls -> fls fls fls -> fls
or = λb.λc. b tru c
or tru fls
= (λb.λc. b tru c) tru fls
-> (λc. tru tru c) fls
-> tru tru fls
= (λt.λf. t) tru fls
-> (λf. tru) fls
-> fls
or tru tru -> (λb.λc. b tru c) tru tru -> tru tru tru -> tru
or tru fls -> (λb.λc. b tru c) tru fls -> tru tru fls -> tru
or fls tru -> (λb.λc. b tru c) fls tru -> fls tru tru -> tru
or fls fls -> (λb.λc. b tru c) fls fls -> fls tru fls -> fls
not = λb. b fls tru
not fls
= (λb. b fls tru) fls
-> fls fls tru
= (λt.λf. f) fls tru
-> (λf. f) tru
-> tru
not tru -> (λb. b fls tru) tru -> tru fls tru -> fls
not fls -> (λb. b fls tru) fls -> fls fls tru -> tru
The natural numbers can be represented by applying a successor function s
multiple times to a zero function z
.
c₀ = λs.λz. z
c₁ = λs.λz. s z
c₂ = λs.λz. s (s z)
c₃ = λs.λz. s (s (s z))
...
It is interesting to note that the definition of c₀
is the same as the definition of fls
.
We can form a successor function scc
by adding an additional application of s
to a number n
:
scc = λn.λs.λz. s (n s z)
Here is a demonstration of how scc c₂
evaluates to its successor, c₃
:
scc c₂
= (λn.λs.λz. s (n s z)) c₂
-> λs.λz. s (c₂ s z)
= λs.λz. s ((λs.λz. s (s z)) s z)
-> λs.λz. s (s (s z)))
= c₃
add = λm.λn.λs.λz. m s (n s z)
You can think of this like dopping replacing z
at the end of m
with the number n
.
add c₂ c₁
= (λm.λn.λs.λz. m s (n s z)) c₂ c₁
-> (λn.λs.λz. c₂ s (n s z)) c₁
-> λs.λz. c₂ s (c₁ s z)
= λs.λz. (λs.λz. s (s z)) s ((λs.λz. s z) s z)
-> λs.λz. (λs.λz. s (s z)) s (s z)
-> λs.λz. s (s (s z))
= c₃
mul = λm.λn.λs.λz. m (add n) c₀
Here we apply add n
an m
number of times to c₀
to obtain the product.
mul c₃ c₂
= (λm.λn.λs.λz. m (add n) c₀) c₃ c₂
-> λs.λz. c₃ (add c₂) c₀
TaPL, Figure 5.3:
t ::= terms:
x variable
λx. t abstraction
t t application
v ::= values:
λx. t abstraction value
t₀ ⟶ t'₀
─────────────────── (T-App1)
t₀ t₁ ⟶ t'₀ t₁
t₁ ⟶ t'₁
─────────────────── (T-App2)
v₀ t₁ ⟶ v₀ t'₁
(λx. t₀₁)v₁ ⟶ [x ⟼ v₁]t₀₁ (E-AppAbs)