Skip to main content

Chapter 1: Introduction

Overview

The lambda calculus can be thought of as the theoretical foundation of functional programming. It is a Turing complete language.

The lambda calculus expressions (Λ\Lambda) consist of following three types of elements:

Variables: If x is a variable, then xΛAbstractions: If x is a variable, and MΛ, then λx.MΛApplications: If MΛ and NΛ, then MNΛ\begin{array}{lll} \text{Variables: }&\text{If } x \text{ is a variable, then }& x\in\Lambda\\ \text{Abstractions: }&\text{If } x \text{ is a variable, and } M \in \Lambda \text{, then }& \lambda x. M\in\Lambda\\ \text{Applications: }&\text{If } M \in \Lambda \text{ and } N \in \Lambda \text{, then }& M N\in\Lambda\\ \end{array}

Don't worry about obscure mathematical definition above, let's learn it by examples.

Lambda Function

Let's take an anonymous function for example:

x2x^2

Substitute 77 for xx:

x2x=7=49x^2|_{x=7}=49

Similar function donated in lambda calculus requires explicit indication of parameter as:

λx.x2\lambda x.x^2

Substitution is renamed to application with another syntax similar to multiplication in regular mathematics:

(λx.x2)7=49(\lambda x.x^2)7=49

A name could also be assigned to the function like this:

f(x)=x2f(7)=49f(x)=x^2\\ f(7)=49

In lambda calculus, it should be rewritten as:

f=λx.x2f7=49f=\lambda x.x^2\\ f7=49

At the first glance, you may be confused. Don't worry, let's check it in detail.

Compare following two expressions:

x=7f=λx.x2x=7\\ f=\lambda x.x^2

We may say, xx is a variable, whose value equals 77.

Similarly, let's say, ff is also a variable, whose value equals a function.

It reveals one of core ideas about lambda calculus. That is, functions are also variables. You will get accustomed to this soon.

There are some conventions of named functions. For example:

I=λx.xI=\lambda x.x

Identity function II returns its parameter unchanged. It will be mentioned again later.

Function as Return Value

Since now functions are also variables, please view following example:

f=λx.λy.(x+y)f3=λy.(3+y)(f3)4=3+4=7f=\lambda x.\lambda y.(x+y)\\ f3=\lambda y.(3+y)\\ (f3)4=3+4=7

ff is a function whose return value is also a function. Just like normal value functions, whose return value is determined by its parameters, the function returned by ff is also determined by its parameter xx. f3f3 is "plus 3 function" and f4f4 is "plus 4 function". Then we may apply it again with another parameter to obtain further result.

Free variables are those whose value is not determined by its direct enclosing function. Free variable of inner function taking the value from outer function is called capture.

Currying and Uncurrying

If we treat consecutive lambda function chain as one multiple-parameter function:

λx.λy.λz.Mcurryinguncurryingλxyz.M\lambda x.\lambda y.\lambda z.M\overset{\text{uncurrying}}{\underset{\text{currying}}{\rightleftarrows}}\lambda xyz.M

We may review the previous example from another perspective:

f=λxy.(x+y)f 3=λy.(3+y)(2)f 3 4=3+4=7\begin{array}{lr} f=\lambda xy.(x+y)\\ f\space3=\lambda y.(3+y)&(2)\\ f\space 3\space 4=3+4=7 \end{array}

Pay attention to the line (2)(2). It partially applies the function with only first parameter and yields a function taking successive ones, which is called partial application. In fact, the definition of partial application of uncurrying multiple-parameter function is exactly corresponding to the practice of application of currying consecutive lambda function chain - as if it is.

From the one perspective of associativity, application is also similar to multiplication in regular mathemtics just as syntax do - contiguous operands should be applied from left to right. That is,

ABC=(AB)CABC=(AB)C

represents apply AA with BB, and apply previous result with CC.

From the other persepctive of currying and uncurrying, left side of equation reprensents apply AA with BB together and right side of equation represents apply it step by step. But at the end of day, they are equivalent and no more than two different ways to understand the same application process.

Function as Parameter

Similarly, functions could be passed as parameters, too:

F=λfx.fxxf=λxy.(x+y)Ff2=(λfx.fxx)(λxy.(x+y))2=(λxy.(x+y))2 2=4F=\lambda fx.fxx\\ f=\lambda xy.(x+y)\\ \begin{array}{} Ff2&=&(\lambda fx.fxx)(\lambda xy.(x+y))2\\&=&(\lambda xy.(x+y))2\space2\\&=&4 \end{array}

It is remarkable that FfFf produces a new function from an old one. Isn't it cool to manipulate functions instead of just values?

Reduction

To simplify lambda calculus expressions, three kinds of reductions will be introduced.

Alpha reduction

λx.x=λy.y\lambda x.x = \lambda y.y

α\alpha reduction is also known as α\alpha equivalence. Substitution of parameter name does not change semantics. It is similar to following cases in regular mathematics:

f(x)=x2f(y)=y2f(x)=x^2\equiv f(y)=y^2\\ 01ug(u)du=01vg(v)dv\int_0^1ug(u)du=\int_0^1vg(v)dv i=1ai=j=1aj\sum_{i=1}^\infty a_i=\sum_{j=1}^\infty a_j

Note despite semantics unchanged, name conflicts and shadowing may casue ambiguity and confusion:

λx.λy.y=λx.λx.x ?\lambda x.\lambda y.y=\lambda x.\lambda x.x\space?

It is more damaging than those cases in regular mathematics:

F(x)=xf(x)dxF(x)=\int_{-\infty}^xf(x)dx

Beware outer xx and inner xx are differnet ones.

Beta reduction

(λx.x)y=y(\lambda x.x)y = y

This is exactly what application is all about. Most common reduction during lambda calculus is the β\beta reduction.

Note that a constant function cannot be reduced to the constant even if the constant is independent from the parameter. An application is necessary.

λx.cc(λx.c)y=c\lambda x.c\neq c\\ (\lambda x.c)y= c\\

Eta reduction

λy.xy=x\lambda y.xy=x

η\eta reduction is not that obvious. To prove this equation, we'd better introduce a helper variable zz to be applied with:

(λy.xy)z=xz(\lambda y.xy)z=xz

Applying them with identical parameter yield identical result. That's why they are considered equivalent.