Curry–Howard and typed lambda calculus
Build typed proof terms, perform capture-avoiding substitution, and interpret reduction as simplifying a derivation.
On this page
The question for today
What you’ll understand
- Derive function introduction and application judgments from a typed context.
- Normalize a concrete typed term using capture-avoiding substitution.
- Distinguish proof construction, proof checking, and execution within a fixed calculus.
A derivation can be recorded as a program whose type states the proposition it proves. Function abstraction records an implication introduction, and application records its elimination. This correspondence gives proofs an explicit syntax that can be substituted, simplified, and checked. The word correspondence refers to a specified logical and computational calculus: adding exceptions, unrestricted recursion, or new axioms changes the account. We begin with a small typed language where the connections can be inspected one rule at a time.
Contexts record the assumptions a term may use
A typing judgment says that a term has a type under a context of named assumptions. For the simply typed fragment, types are built from fixed base types and function types; we also use Boolean constants and their case operator. To introduce a function, temporarily assume an input of its domain and derive a body of its codomain. Discharging that named assumption creates an abstraction. To apply a function, the supplied argument must have its declared domain type.
The context prevents a proof from using unexplained information. A free variable is an outstanding assumption, while a closed term has none. The same term shape may describe a logical proof or a small program depending on the interpretation of its base types. Type checking verifies a proposed derivation; it does not automatically invent its term. Later claims about termination will apply to this total fragment, not to arbitrary code merely written with function notation.
Substitution explains the computational rule
Applying an abstraction replaces its bound variable by the supplied argument. Substitution must avoid capturing free variables of that argument. For example, substituting a free y for x in an abstraction that already binds y requires first renaming the inner binder. This renaming changes the spelling of a bound name without changing the represented function. Ignoring that step can turn a constant function into an identity function and invalidate both the computation and the corresponding proof transformation.
The substitution lemma connects syntax with typing: if the body is well typed using an assumption of type A, and the replacement has type A in the surrounding context, then the substituted body retains its promised type. This lemma underlies preservation for beta reduction. It is not a statement that every informal replacement of symbols is valid. Dependencies, variable scopes, and annotations determine which substitutions are legitimate, particularly once types themselves begin to depend on terms.
Proof composition is function composition
Given a proof of A implying B and a proof of B implying C, introduce a hypothetical A, apply the first proof, then apply the second. Abstracting the hypothetical input yields a proof of A implying C. The constructed term makes the order of use explicit. Reversing the two applications usually fails to type check, even if an informal description merely says to combine the implications. Logical composition therefore has a precise interface rather than an interchangeable sequence of steps.
Reduction removes an introduction immediately followed by its matching elimination. In proof language this simplifies a detour; in program language it computes a result. These views reinforce each other without asserting that every proof system has the same evaluation strategy or proof equality. For example, two functions that return the same Boolean on both inputs may need a separate extensional argument in a theory whose judgmental equality only uses the declared reduction rules. We will keep that distinction when studying identity types.
Work it through
Type and evaluate a higher-order Boolean term
Let neg exchange true and false. Type the function that applies a supplied Boolean function twice, then evaluate it on neg and false. Explain which equalities come from the rules of this language.
Assume h is a function from Bool to Bool and b is a Boolean. Applying h to b gives a Boolean, so applying h again is legal. Abstraction over b and then h gives a term of type (Bool→Bool)→Bool→Bool.
Supply neg for h and false for b. Two beta reductions expose neg applied to neg of false. The inner Boolean case returns true and the outer case returns false.
The resulting closed term reduces to false by the declared application and Boolean computation rules. This is a computation of this particular expression; an assertion about an arbitrary unknown Boolean function would require additional assumptions.
The double-application combinator has the expected higher-order type, and applying it to Boolean negation and false computes to false.
The living notebook
Explore the model
Interactive lab · function
Read the input and output of a fixed function
Pause and Reset, then set coefficient a to 0.5 and position x to 2. Predict value 2 and slope 2 for this particular quadratic function. For a fresh comparison Reset and set a to 0.5 and x to 1: value is 0.5 and slope 1. Treat these as inspectable input/output examples, not as a visualization of lambda syntax or Boolean reduction. Both displayed quantities are computed from the actual quadratic model. Parameter edits preserve the clock; Reset and set both controls for each run.
- y at chosen x
- 0.608
- Tangent slope · 2ax
- 1.35
- Signed area · ax³/3
- 0.182
This lab uses only y = ax². Playback traces the curve within the fixed integration interval from 0 to x; it does not estimate numerical error or change the chosen point. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forA function has specified inputs and outputs; a few observed values do not replace a typed definition or a proof about every input.
Pause & reason
Check your understanding
Your turn
Try it yourself
Construct a closed term of type A→B→A. Derive its type from a context, and evaluate its application to assumptions a:A and b:B without capturing either variable.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Under assumptions x:A and y:B, you already possess a term of type A. Discharge the assumptions in reverse order.
Compare with the solution
Use the term λx:A.λy:B.x. In the context x:A,y:B the variable rule gives x:A; abstraction over y yields B→A and abstraction over x yields A→B→A. Applying the closed term to a gives λy:B.a, and applying that to b gives a. Fresh binder names may be chosen first if either supplied term contains a conflicting free name. The term ignores its second argument without needing any evidence of B beyond the argument supplied at application.
Keep the idea
Take it with you
- A typing context exposes every available assumption.
- Beta reduction uses capture-avoiding substitution and preserves typing.
- Curry–Howard relates specified logical and computational rules, not every programming feature indiscriminately.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.