Site icon

Building Stuff with Lambda Calculus

Common kestrel and black-shouldered kite.

The Kestrel and the Kite. Photos by Jakub Hałun and Charles J. Sharp.

One of us always lies, and one of us always tells the truth.

— The Kestrel

A lambda is just a different way of writing a function. Like normal functions, it takes argument(s) and returns something. The expression λa.a reads as “takes a single argument a, and returns argument a”. This is the simplest lambda and it is the equivalent of f(x)=xf(x) = x. It can take expression x as an argument from the right like so,

λa.a x => x.

This reads as “a function—which takes a and returns a—takes x and returns x”. That little => just means “becomes” or “can be reduced to”.

You can express all sorts of concepts in math and programming using just lambdas. Lets pick the coolest ones and build them from first principles.

A Flock of Functions #

Below are your standard named lambdas.

The Kite for example takes two arguments and returns the first one. It can take expressions x and y like so,

λab.a x y => λb.x y => x.

Note that arguments can be fed into functions one at a time. This one reduces in two steps.

Booleans (Church-encoded) #

We can express boolean logic just with lambdas. Recall the pattern

if boolean then x else y

In the context of an if statement, the essence of a boolean is a function that selects between two arguments. Well, that’s what we have in the Kestrel and the Kite.

Take the expression BOOL x y. If BOOL = TRUE, then this reduces to x. If BOOL = FALSE, then this reduces to y. This is what an if statement does.

We can also do boolean logic.

NOT TRUE = FALSE

See if you can understand why this is true. We also have OR and AND.

Natural Numbers (Church-encoded) #

ZERO f x = x
SUCC ZERO = 1
SUCC 1 = 2
SUCC = SB
     = (λabc.ac(bc)) B
     = λbc.(λxyz.x(yz)) c(bc)
     = λbc.λz.c((bc)z)
     = λbcz.c(bcz)
     = λnfx.f(nfx)
     = λnf.λx.f((nf)x)
     = λnf.(λabx.a(bx)) f(nf)
     = λcnf.cf(nf) (λabx.a(bx))
     = λnfx.Bf(nf)x
EXP 3 2 = 2 3

“Twice thrice” = 9.

MUL 3 2 = λc.3(2 c) = λc.6 c = 6

Pairs #

FST (PAIR 1 2) = 1
SND (PAIR 1 2) = 2

More Numerals #

Lists (cons-cell) #

Lists (Church-encoded) #

Folding is part of the structure of these lists. List [1, 2, 3] can be represented by

CONS 1 (CONS 2 (CONS 3 NIL)) = λcn.c 1 (c 2 (c 3 n))

To sum a list you therefore do

(λcn.c 1 (c 2 (c 3 n))) ADD 0

Example #

CONS 3 NIL = λhtcn.ch(tcn) 3 NIL
           = λtcn.c3(tcn) NIL
           = λcn.c 3(NIL cn)
           = λcn.c 3 n

CONS 4 (CONS 3 NIL) = λhtcn.ch(tcn) 4 (λcn.c 3 n)
                    = (λtcn.c 4 (tcn)) (λcn.c 3 n)
                    = λcn.c 4 ((λcn.c 3 n) c n)
                    = λcn.c 4 (c 3 n)

FOLD ADD 0 (CONS 4 (CONS 3 NIL)) = (λfzl.lfz) ADD 0 (λcn.c 4 (c 3 n))
    = (λcn.c 4 (c 3 n)) ADD 0
    = (λn. ADD 4 (ADD 3 n)) 0
    = ADD 4 (ADD 3 0)
    = ADD 4 3
    = 7

Option Monad #

maybe1 = NONE

maybe2 = SOME 5
       = (λxsn.sx) 5
       = λsn.(s 5)

ISSOME NONE = KI

ISSOME (SOME val) = (λo.o(KK)KI) λsn.(s val)
                  = λsn.(s val)(KK)KI
                  = KK val
                  = (λab.a)K val
                  = K

Recursion #

Y = λf.(λx.f(xx))(λx.f(xx))