VIASM Mini-Course · Hanoi 2026 · Lecture 1

A general introduction to type theory

A proof is a term, a theorem is its type, and checking the proof is type-checking the term.

dr Bartosz Naskręcki · Adam Mickiewicz University in Poznań · CCAI, Warsaw Univ. of Technology

▷ live lab: /lab-lambda

Why this matters

A proof assistant must answer one question mechanically: is this a proof? The trick that makes it decidable is startlingly economical.

A proof is a term · a theorem is its type · checking the proof is type-checking the term.

Everything in this course — Lean, Rocq, Agda, and the contrast with Mizar — works out that one sentence, built up from the untyped $\lambda$-calculus.

Where we are going

  • Judgments $\Gamma \vdash t : A$ and the three STLC typing rules
  • Metatheory: subject reduction and strong normalization
  • Church vs Curry style; principal types
  • The Curry–Howard correspondence: proofs = programs
  • Why types are almost sets — and the three places it breaks
  • Dependent types, Martin-Löf type theory, and the four provers

Judgments, contexts, typing rules

Type theory is a game of judgments. The central one:

$$ \Gamma \vdash t : A \qquad\text{“in context } \Gamma\text{, term } t \text{ has type } A\text{.”} $$

Types: $\;A, B ::= o \mid A \to B\;$ (arrow right-associative). Three rules generate every derivable judgment:

$$ \frac{(x:A)\in\Gamma}{\Gamma\vdash x:A}\,(\textsf{var}) \quad \frac{\Gamma, x{:}A \vdash t:B}{\Gamma\vdash \lambda x{:}A.\,t : A\to B}\,(\textsf{abs}) \quad \frac{\Gamma\vdash t:A\to B \quad \Gamma\vdash u:A}{\Gamma\vdash t\,u:B}\,(\textsf{app}) $$

abs builds a function type; app eliminates one. A derivation is a finite tree whose leaves are (var).

A derivation by hand

Type “apply $f$ twice” — the Church numeral $\overline{2}$ — writing $\Gamma = f{:}o{\to}o,\ x{:}o$:

$$ \frac{ \dfrac{}{\Gamma\vdash f : o\to o}\,(\textsf{var}) \qquad \dfrac{\dfrac{}{\Gamma\vdash f:o\to o}\ \dfrac{}{\Gamma\vdash x:o}}{\Gamma\vdash f\,x:o}\,(\textsf{app}) }{\Gamma\vdash f\,(f\,x):o}\,(\textsf{app}) $$

Discharge both assumptions with (abs), innermost first:

$$ \vdash\ \lambda f{:}o{\to}o.\,\lambda x{:}o.\,f\,(f\,x)\ :\ (o\to o)\to o\to o. $$

Metatheory: what typing buys you

The rules are cheap; their consequences are the whole point.

  • Uniqueness (Church). If $\Gamma\vdash t:A$ and $\Gamma\vdash t:B$ then $A=B$ — checking is deterministic.
  • Subject reduction. If $\Gamma\vdash t:A$ and $t\to_\beta t'$ then $\Gamma\vdash t':A$ — types survive computation. Engine: the substitution lemma.
  • Strong normalization (Tait 1967). Every well-typed term halts — no infinite $\to_\beta$ sequence.

Consequence: $\Omega=(\lambda x.\,x\,x)(\lambda x.\,x\,x)$ and the $Y$-combinator are untypable. STLC trades Turing-completeness for guaranteed termination — and type-checking is decidable.

ch term \x. x x

Watch inference fail live: unifying $\alpha$ with $\alpha\to\beta$ trips the occurs check — the REPL reports “Cannot unify α with α → β”. Self-application has no simple type, so neither $\Omega$ nor $Y$ (which is built from self-application) does.

Church vs Curry: two readings, one system

Church style

Variables carry their type: $\lambda x{:}A.\,t$. Every term has at most one type. Typing is checking. — modern kernels.

Curry style

Bare untyped terms; a type is assigned after the fact. A term may have many types. Typing is inference.

Related by type-erasure $|\cdot|$. Organizing fact: the principal type. The identity $\lambda x.\,x$ has infinitely many types, all instances of one most-general $\alpha \to \alpha$.

ch term \p. p

Algorithm W, live: the Curry principal type $\alpha\to\alpha$; then ch lean \p. p for the Church-style Lean term fun p => p : P → P — one object, two readings, related by erasure.

Principal-type theorem (Hindley 1969, Milner 1978): computable by unification — the heart of Hindley–Milner inference in ML, Haskell, Lean's elaborator.

The Curry–Howard correspondence

The conceptual centre: a dictionary between logic and computation.

  • proposition $P$  $\leftrightarrow$  type $P$
  • proof of $P$  $\leftrightarrow$  term $t:P$
  • $P \to Q$  $\leftrightarrow$  function $P\to Q$
  • $P \land Q$  $\leftrightarrow$  product $P\times Q$
  • $P \lor Q$  $\leftrightarrow$  sum $P + Q$
  • $\forall x{:}A.\,P$  $\leftrightarrow$  $\textstyle\prod_{x:A} P$
  • $\exists x{:}A.\,P$  $\leftrightarrow$  $\textstyle\sum_{x:A} P$
  • normalization  $\leftrightarrow$  $\beta$-reduction

Provability = inhabitation: $A$ is intuitionistically provable iff its type has a closed term. This is the engine of every prover in the course.

Transitivity of implication is composition

The tautology $(P\to Q)\to(Q\to R)\to P\to R$ is inhabited — its proof term is function composition (the $B$ combinator):

$$ \lambda f.\,\lambda g.\,\lambda p.\,g\,(f\,p). $$

theorem trans_imp {P Q R : Prop} : (P → Q) → (Q → R) → P → R :=
  fun f g p => g (f p)

“Chaining implications” and “composing functions” are one operation. The proof is the program.

prove (P -> Q) -> (Q -> R) -> P -> R

Build it yourself with intro/apply/exact; qed prints exactly $\lambda f\,g\,p.\,g\,(f\,p)$ and its type.

Peirce's law has no proof term

$\,((P\to Q)\to P)\to P\,$ is a classical tautology, yet no closed STLC term inhabits it. Try to build one and you get stuck: with $P,Q$ atomic, no rule makes a $Q$.

theorem peirce {P Q : Prop} : ((P → Q) → P) → P :=
  fun h => Classical.byContradiction (fun hnp => hnp (h (fun hp => absurd hp hnp)))

Delete Classical and it fails to type-check. Curry–Howard yields intuitionistic proofs; excluded middle is an axiom you opt into, not a theorem.

Types are not (quite) sets

Read a type as the set of its closed normal terms: $[\![A\times B]\!]$ a product, $[\![A+B]\!]$ a disjoint union, $\bot=\varnothing$. For STLC this is honest. But it breaks three ways:

  • Proof relevance. Elements are proofs; $a\equiv b$ (computes to) $\ne$ $a=b$ (a theorem, an inhabitant of an identity type).
  • No set of all sets. $\mathsf{Type}:\mathsf{Type}$ is inconsistent — Girard's paradox (Hurkens 1995). Fix: universe hierarchy $\mathsf{U}_0:\mathsf{U}_1:\cdots$.
  • Constructive existence. An inhabitant of $\sum_{x:A}B(x)$ carries an actual witness.

Install the caveat the same hour as the intuition — each break motivates something later.

A first look at dependent types

Let a type depend on a value — e.g. length-indexed vectors $\mathsf{Vec}\,A\,n$. Two constructors:

  • $\Pi$-type $\;\prod_{x:A}B(x)\;$ — result type varies with input; realizes $\forall x{:}A.\,B(x)$. Constant $B$ = ordinary $A\to B$.
  • $\Sigma$-type $\;\sum_{x:A}B(x)\;$ — pair $\langle a,b\rangle$ with $b:B(a)$; realizes the witness-carrying $\exists x{:}A.\,B(x)$, with $\pi_1\langle a,b\rangle=a$.

A theorem like $\mathsf{cons}: A\to\mathsf{Vec}\,A\,n\to\mathsf{Vec}\,A\,(n{+}1)$ becomes a typing. Barendregt's $\lambda$-cube organizes the design space; its apex $\lambda C$ (Calculus of Constructions) is the ancestor of Lean's and Rocq's CIC.

$\exists$ as a $\Sigma$ with a real witness

A constructive proof of “there is an $n$ with $n+n=4$” is a pair: the witness $2$, and evidence that $2+2=4$ — which is refl, since both sides compute to the same numeral.

∃-even : Σ ℕ (λ n → n + n ≡ 4)
∃-even = 2 , refl

Its first projection returns $2$ — exactly what a classical non-emptiness proof cannot give you. In Martin-Löf type theory, $\mathbb{N}$-elimination is mathematical induction, now a primitive term former.

Why type theory underlies modern provers

  • Small trusted kernel (de Bruijn criterion) — proofs sound even if tactics are buggy.
  • Computation is native — $2+2$ and $4$ are the same type by conversion.
  • Extraction — the proof is the algorithm.
  • Theorems are types — you prove by inhabiting.

Lean 4 · CIC · classical (Mathlib)

Rocq · CIC + SProp · constructive core

Agda · predicative MLTT · constructive

Mizar · Tarski–Grothendieck set theory · no proof terms

Three type theories, one set theory — an engineering choice, not a coronation. Mizar verifies deep mathematics with no proof terms at all.

Run it yourself

See the correspondence — don't take it on faith. In the browser Lambda Lab, view a proof term and open it in Live Lean:

lean imp_comp

prints theorem imp_comp {P Q R : Prop} (f : P → Q) (g : Q → R) : P → R := fun p => g (f p) — exactly $\lambda f\,g\,p.\,g\,(f\,p)$ — with a live.lean-lang.org link. For Peirce's law,

kb intuitionistic

explains why it needs a classical principle — then let the lab settle it live:

ch type '((P -> Q) -> P) -> P'

reports Peirce's law uninhabited: exhaustive search finds no closed term. (Desktop lab only: ch verify re-checks the emitted Lean against a local Lean toolchain.)

Recap & references

  • Judgment $\Gamma\vdash t:A$, three STLC rules; subject reduction + strong normalization.
  • Church vs Curry, principal types; Curry–Howard: provability = inhabitation.
  • Types $\approx$ sets, until proof-relevance, Girard's paradox, constructive $\exists$.
  • $\Pi/\Sigma$ dependent types, MLTT, and four provers on three type theories + one set theory.

Pierce, TAPL · Sørensen–Urzyczyn, Curry–Howard Isomorphism · Girard–Lafont–Taylor, Proofs and Types · Wadler, Propositions as Types · Martin-Löf, Intuitionistic Type Theory · the four-prover artifacts at github.com/nasqret/vietnam2026