Enter the vast world of programming languages by following the tutorials provided here to learn about functional programming in Haskell.
In most programming languages, the use of conditionals is very common. For example, if we want to choose the smaller number of two numbers, we write the following (pseudo-) code:
if x < y then x else y
If x is less than y, we take the then branch. However, if x isn’t less than y, we take the else branch. Also, as we can see, the if clause always evaluates a TRUE or FALSE statement. Thus, if we want to implement this logic in lambda calculus, we need to do things:
Let’s tackle the latter issue first.
We can represent TRUE and FALSE in lambda calculus by defining them as follows:
TRUE := λx.λy. x FALSE := λx.λy. y
Now, it might not mean much now, but once we have a way of implementing if-then-else logic, hopefully it will become more clear.
Now, if-then-else takes in three arguments:
Thus, we can represent if-then-else in lambda calculus by using a abstraction with three binders as follows:
IF-THEN-ELSE := λx.λy.λz. x y z
This seems like a fairly standard abstraction with three binders, so how could this possibily give us our desired logic? Well, let’s combine it with our definitions of TRUE and FALSE
(λx.λy.λz. x y z) (λx.λy. x) p q
(λx.λy.λz. x y z) (λx.λy. y) p q
Now, the first statement represents
if TRUE then p else q
Let’s use our beta-reduction rules to see how this is the case.
(λx.λy.λz. x y z) (λx.λy. x) p q
→ (λy.λz. (λx.λy. x) y z) p q
→ (λz. (λx.λy. x) p z) q
→ (λx.λy. x) p q
→ (λy. p) q
→ p
As we can see, we take the then branch because our boolean expression in the if clause is TRUE. The same can be done for the second statement.
(λx.λy.λz. x y z) (λx.λy. y) p q
→ (λy.λz. (λx.λy. y) y z) p q
→ (λz. (λx.λy. y) p z) q
→ (λx.λy. y) p q
→ (λy. y) q
→ q
The beauty of lambda calculus, however, is that we don’t have to stop here. We can even define lambda expressions for AND, OR, and NOT.
If you are unfamilar with AND, OR, and NOT, that is ok.
AND, OR, and NOT are operators with the following truth tables (we will be dealing with AND2 and OR2 for simplicity):
Input 1 | Input 2 | Output |
FALSE | FALSE | FALSE |
FALSE | TRUE | FALSE |
TRUE | FALSE | FALSE |
TRUE | TRUE | TRUE |
Input 1 | Input 2 | Output |
FALSE | FALSE | FALSE |
FALSE | TRUE | TRUE |
TRUE | FALSE | TRUE |
TRUE | TRUE | TRUE |
Input | Output |
FALSE | TRUE |
TRUE | FALSE |
Thus, we define AND, OR, and NOT in lambda calculus as follows:
AND := λx.λy. x y x
OR := λx.λy. x x y
NOT := λx. (λp.λq. q) (λp.λq. p) = λx. FALSE TRUE
As an exercise, I would like you to verify these defintions of AND, OR, and NOT by using the truth tables above in addition to the defintions of TRUE and FALSE. Once you have done that, we can begin learning about De Bruijn indices.