Overview: The “Warehouse” of Computation
If the Lambda Calculus is an elegant mathematical dream where everything is a pure, side-effect-free function evaluating to a value, IMP is the blue-collar reality of moving boxes around in a warehouse.
IMP is the theoretical “Hello World” of imperative languages. It strips away objects, types, and functions to leave only the bare essentials of how languages like C, Java, or Python actually execute: commands mutating memory over time.
In λ-calculus, computation is rewriting the code itself (β-reduction). In IMP, the code remains completely static. Instead, the code issues orders that mutate an invisible, external environment.
1. Syntax
IMP is built on three syntactic pillars: Arithmetic (AExp), Booleans (BExp), and Commands (Com). Commands are the only constructs that actually do things (cause side effects). Assuming variables x∈Var and integers n∈Z:
Arithmetic Expressions (AExp): (Evaluate to integers, no side effects)
a::=n∣x∣a1+a2∣a1−a2∣a1×a2
Boolean Expressions (BExp): (Evaluate to truth values, no side effects)
b::=true∣false∣a1=a2∣a1≤a2∣¬b∣b1∧b2
Commands (Com): (Do not evaluate to values; they mutate state)
c::=skip∣x:=a∣c1;c2∣if b then c1 else c2∣while b do c
2. Configurations and State
Unlike pure λ-calculus (which relies on α-conversion and environment closures), IMP relies on a mutable State (or store) to track variables.
- State (σ): A partial function mapping variables to integers, σ:Var→Z.
- Configuration: A tuple ⟨c,σ⟩ representing the current point of execution.
- State Update: σ[x↦n] denotes a new state identical to σ, except that the variable x now maps to the integer n.
But why model State (
σ) as a map?
In a physical computer, RAM is essentially a massive array of bytes, accessed via integer memory addresses. Theoretical computer science abstracts this away:
- Variables as Addresses: Instead of raw hex addresses, we use human-readable variable names (x,y,z∈Var).
- Values as Contents: Instead of binary bytes, we use infinite-precision integers (n∈Z).
Therefore, the cleanest mathematical abstraction of a computer’s memory (or a CPU’s registers) is a partial function (a map) from variables to integers:
σ:Var→ZKey Insight: When you write x:=5, you aren’t substituting 5 into x everywhere in the code (like in λ-calculus). The code stays x:=5. Instead, you are updating the map. The notation σ[x↦n] means “a brand new state map that is identical to σ in every way, except if you query x, it now returns n.”
3. Big-Step Semantics (Natural Semantics)
Big-step semantics skip the intermediate machinery and tell you the final result. It reads like writing a standard recursive interpreter.
The judgment ⟨c,σ⟩⇓σ′ means: “If you run command c starting with memory σ, it will eventually terminate and leave memory in state σ′.”
(Note: ⇓a evaluates arithmetic to an integer; ⇓b evaluates booleans to true/false).
Skip & Assignment:
⟨skip,σ⟩⇓σ⟨x:=a,σ⟩⇓σ[x↦n]⟨a,σ⟩⇓an
Sequencing (Do c1, then do c2):
⟨c1;c2,σ⟩⇓σ′⟨c1,σ⟩⇓σ′′⟨c2,σ′′⟩⇓σ′
If-Then-Else:
⟨if b then c1 else c2,σ⟩⇓σ′⟨b,σ⟩⇓btrue⟨c1,σ⟩⇓σ′
⟨if b then c1 else c2,σ⟩⇓σ′⟨b,σ⟩⇓bfalse⟨c2,σ⟩⇓σ′
While Loop:
⟨while b do c,σ⟩⇓σ⟨b,σ⟩⇓bfalse
⟨while b do c,σ⟩⇓σ′⟨b,σ⟩⇓btrue⟨c,σ⟩⇓σ′′⟨while b do c,σ′′⟩⇓σ′
4. Small-Step Semantics (Structural Operational Semantics)
Big-step is great, but it has a fatal flaw: it cannot describe non-terminating programs (infinite loops) or concurrency, because there is no “final state” to return.
Small-step semantics fixes this by modeling computation as a sequence of discrete, atomic ticks of a clock: ⟨c,σ⟩→⟨c′,σ′⟩. This is the imperative equivalent of step-by-step β-reduction.
Assignment:
(Assuming expression a has already reduced step-by-step to integer n)
⟨x:=n,σ⟩→⟨skip,σ[x↦n]⟩
Sequencing:
⟨c1;c2,σ⟩→⟨c1′;c2,σ′⟩⟨c1,σ⟩→⟨c1′,σ′⟩
⟨skip;c2,σ⟩→⟨c2,σ⟩
If-Then-Else:
⟨if true then c1 else c2,σ⟩→⟨c1,σ⟩
⟨if false then c1 else c2,σ⟩→⟨c2,σ⟩
While Loop (The unrolling trick):
(Instead of resolving the whole loop, small-step simply unwraps one iteration and converts it into an if-statement. This allows infinite loops to just keep unrolling forever without breaking the math).
⟨while b do c,σ⟩→⟨if b then (c;while b do c) else skip,σ⟩