
Lambda Calculus · v1.0.2
2026-09-28 02:12:33
Start from Python, and take three things away:
Everything else in this module is a consequence of those three.
Nothing is lost. Every computable function can still be expressed.
The restriction that looks like a loss is what makes concurrency safe.
Functional programming is an approach to programming based on function calls as the primary programming construct.
The theory is clean because the style started as theory.
This is function composition, or nesting.
A calculator cannot generalise: to repeat a calculation with different values, re-enter the whole thing.
Both styles agree this far. They part over what a name is allowed to do.
The imperative rule
A variable: a changeable association between a name and values.
\[\langle name \rangle = \langle expression \rangle\]
The same name may hold different values.
The functional rule
Names are introduced only as formal parameters, bound by actual parameters.
A name is only ever associated with one value.
Time does not enter.
x does f see?Two defensible answers, and languages differ on which they give.
Lexical scoping
f sees the x where f was written.
g() is 1.
Dynamic scoping
f sees the x of whoever called it.
g() is 2.
Lexical scoping is what makes “look at where it was bound” a complete answer.
To swap x and y:
Permute the same three commands and the program changes:
x = y; t = x; y = t sets x to yt = x; y = t; x = y sets y to xSame three commands, three different programs.
\[f(a(d),\ b(d),\ c(d))\]
a, b and c cannot change their common argument d
Whichever order the arguments are evaluated in, f receives the same three values.
The guarantee is a theorem, not an observation.
Order independence is proved, not assumed.
A function calls itself, creating new versions of its parameters.
Both reuse s and i, which is exactly what is unavailable.
For total(b, 0):
i >= len(a)The variable that “changes” in a loop is really a sequence of values. Recursion makes it explicit.
Functional languages provide explicit representations for data structures.
The representation for nested data looks much like nested function calls. In LISP they are the same.
Calls get larger; the flow of data becomes visible rather than hidden in shared state.
Passing a function in is common. Returning one out is rare — and is the point.
arith(ADD) produces a function; (3, 4) applies it.
Functional programming is not a recent style.
The λ calculus was a model of computation before it was a programming language.
Turing showed it is impossible to tell whether an arbitrary Turing machine will halt.
If different evaluation orders do terminate, the results will be the same.
It may be efficient to run some parts in one order and others in another — or in parallel.
Elements of Lambda Calculus — the next unit in this module.
This unit motivates it. The next one defines it.