Let’s get started with some funny things. If we have a function
f(x) = x + 1
, it could be described in lambda
calculus as λx.x+1
.
Something more interesting could be a function accepting two
parameters x
and y
, and returning the
sum of the squares of each parameter. Semantically, we could
express the idea like so: f(x, y) = x^2 + y^2
. In
lambda calculus, we can write it like this:
λx.λy.x^2+y^2
.
Note that instead of one function call we make two calls to a lambda and pass one parameter each, that’s because each lambda function can only accept one argument at a time.
I am going to have a bit of fun, if you allow me, and I am going to rewrite some algebraic functions as lambda expressions:
x - y + 2z
, then
λx.λy.λz.x - y + 2z
-x + 5
, then λx.- x + 5
a^2+b^2-c^2
, then
λa.λb.λc.a^2 + b^2 + c^2
t^2 - π
, then λt.t^2 - π
Let’s perform a substitution in the formula
λx.x + 1
. If we were to plug in a specific value
for x
, we would perform a substitution and it would
be expressed like so: (λx.x + 1) 92
, which we could
evaluate to be 92 + 1 = 93
.
Now that we have handled the arithmetic operations, let’s move
on to other fundamental values/properties in programming. Let’s
start with TRUE
, FALSE
(aka
boolean-type values). Can we represent them in lambda calculus?
We have a few things we can do in lambda calculus:
We can represent each and every data type with these properties.
When it comes to boolean values, we are essentially making a
choice from two elements, we either pick TRUE
or we
pick FALSE
. So we are going to encode this choice
by taking two variables x
and y
and we
shall apply the logic like so:
TRUE = λx.λy.x
FALSE = λx.λy.y
If we pick x
, we shall consider the value to be
TRUE
. If we pick y
, we shall consider
the value to be FALSE
. We have now made this
abstraction around boolean values, but we could likely use it
for any binary choice, such as picking an element from
enum team {red, blue}
.
With logical values defined, we can start defining logical
operations in the lambda calculus. One could think of many
logical operations possible, we shall stick with
NOT
for now, because it’s the simplest logical
operation (the only one that is unary, at least to my knowledge)
and try to define it in the lambda calculus.
NOT = λx.x FALSE TRUE
Well, this came out of nowhere, didn’t it? Let’s examine the
thought process - since NOT
is a unary operation,
we assume it only takes one argument, one parameter, so we
define only one lambda expression.
Let’s see if this NOT
operation of ours works.
Since we are working with boolean values, we can prove it easily
be exhausting all possible values (TRUE
,
FALSE
) in the domain and substituting for them in
the expression. So we take the entire expression and perform a
substitution. We assume the result to be the opposite truth
value for each boolean, so TRUE
if we substitute
with FALSE
and vice versa.
(λx.x FALSE TRUE) FALSE = FALSE FALSE TRUE = λx.λy.y FALSE TRUE = (λx.λy.y) FALSE TRUE = TRUE
As can be seen, the substitution worked. Reader might as well
try it for TRUE
to make sure they get
FALSE
.
Let’s do something more interesting together! How about we
define AND
operation in lambda calculus?
We know since AND
is a binary operation, we shall
probably be using two variables with some constants to arrive at
our derived value. Let us create a triplet of values constructed
out of our variables. Remember, the formula may not be only true
if both x
and y
are true at the same
time. Starting at our first attempt:
(λx.λy.xxx) TRUE TRUE = TRUE TRUE TRUE = (λx.λy.x) TRUE TRUE = TRUE
(λx.λy.xxx) TRUE FALSE = TRUE TRUE TRUE = (λx.λy.x) TRUE TRUE = TRUE
(λx.λy.xxx) FALSE TRUE = FALSE FALSE FALSE = (λx.λy.y) FALSE FALSE = FALSE
(λx.λy.xxx) FALSE FALSE = FALSE FALSE FALSE = (λx.λy.y) FALSE FALSE = FALSE
We have actually got truth values corresponding to the truth
value of x
, but that isn’t what we’re after, let’s
create a triplet where we introduce y
:
(λx.λy.xxy) TRUE TRUE = TRUE TRUE TRUE = (λx.λy.x) TRUE TRUE = TRUE
(λx.λy.xxy) TRUE FALSE = TRUE TRUE FALSE = (λx.λy.x) TRUE FALSE = TRUE
This did not seem to work out, we already got
TRUE
for values of TRUE
and
FALSE
. Let’s shift y
to the left.
(λx.λy.xyx) TRUE TRUE = TRUE TRUE TRUE = (λx.λy.x) TRUE TRUE = TRUE
(λx.λy.xyx) TRUE FALSE = TRUE FALSE TRUE = (λx.λy.x) FALSE TRUE = FALSE
(λx.λy.xyx) FALSE TRUE = FALSE TRUE FALSE = (λx.λy.y) TRUE FALSE = FALSE
(λx.λy.xyx) FALSE FALSE = FALSE FALSE FALSE = (λx.λy.y) FALSE FALSE = FALSE
AND = λx.λy.xyx
It seems we have found an expression for
AND
operation!
Let’s have more fun, and try OR
:
(λx.λy.xxy) TRUE TRUE = TRUE TRUE TRUE = (λx.λy.x) TRUE TRUE = TRUE
(λx.λy.xxy) TRUE FALSE = TRUE TRUE FALSE = (λx.λy.x) TRUE FALSE = TRUE
(λx.λy.xxy) FALSE TRUE = FALSE FALSE TRUE = (λx.λy.y) FALSE TRUE = TRUE
(λx.λy.xxy) FALSE FALSE = FALSE FALSE FALSE = (λx.λy.y) FALSE FALSE = FALSE
OR = λx.λy.xxy
Success! It seems like we could use a challenge, eh? Let’s try
XOR
!
(NOT λx.λy.xy FALSE) TRUE TRUE = NOT TRUE TRUE FALSE = (λx.x FALSE TRUE) TRUE TRUE FALSE = TRUE FALSE TRUE TRUE FALSE = (λx.λy.x FALSE TRUE) TRUE FALSE = TRUE FALSE TRUE = (λx.λy.x) FALSE TRUE = FALSE
(NOT λx.λy.xy FALSE) TRUE FALSE = NOT TRUE FALSE FALSE = (λx.x FALSE TRUE) TRUE FALSE FALSE = TRUE FALSE TRUE FALSE FALSE = (λx.λy.x FALSE TRUE) FALSE TRUE = FALSE FALSE TRUE = (λx.λy.y) FALSE TRUE = TRUE
(NOT λx.λy.xy FALSE) FALSE TRUE = NOT FALSE TRUE FALSE = (λx.x FALSE TRUE) FALSE TRUE FALSE = FALSE FALSE TRUE TRUE FALSE = (λx.λy.y FALSE TRUE) TRUE FALSE = TRUE TRUE FALSE = (λx.λy.x) TRUE FALSE = TRUE
(NOT λx.λy.xy FALSE) FALSE FALSE = NOT FALSE FALSE FALSE = (λx.x FALSE TRUE) FALSE FALSE FALSE = FALSE FALSE TRUE FALSE FALSE = (λx.λy.y) FALSE TRUE FALSE FALSE = TRUE FALSE FALSE = (λx.λy.x) FALSE FALSE = FALSE
XOR = NOT λx.λy.xy FALSE
Phew! Now this was quite a slog to get through! I am sincerely hoping I have not made any mistakes.