Chapter 1
Propositions as Types
A theorem prover has to decide whether a proof is correct. A proof written in English cannot be checked by a computer, so we need a representation of proofs that a program can inspect. This chapter introduces the idea that makes everything else possible: a proof is a program, a proposition is its type, and checking a proof is type checking.
Proofs as programs
Here is a proof, in ordinary mathematical prose, of the proposition " implies ":
Assume . Then ... (some argument) ... so holds.
The shape of this proof is a function. It takes something, a reason to believe , and produces something else, a reason to believe . If we take this literally and treat "a reason to believe " as a value of type , then a proof of is a function from to , and the proposition is the type of that function.
This observation is the Curry-Howard correspondence. It says that
- a proposition is a type,
- a proof of the proposition is a term of that type, and
- the proposition is true exactly when some term of type exists, written .
Three examples show how far this already goes. On the left is a proposition, in the middle a proof of it written as a function, and on the right the idea of the proof in words. Here denotes the function that takes and returns .
| Proposition | Proof | In words |
|---|---|---|
| Return the assumption. | ||
| Ignore the second assumption. | ||
| Compose the two implications. |
Look at the third row again. To prove that implication is transitive, you assume and , and then, given , you apply the first assumption to get and the second to get . The proof term says exactly that: and are the assumptions, is the proof of , and applies them in order. Using an assumption is applying a function; this is the step that distinguishes real reasoning from merely restating hypotheses, and we will return to it in Chapter 3.
Quantifiers become dependent functions
The same idea extends to "for all". To prove that holds for every , we give a method that, handed any particular , produces a proof of . That is again a function, with one twist: its return type depends on the argument. For it returns a proof of , for a proof of . A function type whose result type may mention the argument is called a dependent function type, or a -type, and is written
The ordinary function type is the special case in which does not mention .
For example, "every proposition implies itself" quantifies over propositions. If is the type of propositions, the statement is
and its proof is the function that takes a proposition , then a proof of , and returns :
Notice that the binders now carry types: says that ranges over propositions, and says that is a proof of the particular that was passed in. A type checker will need these annotations.
What the kernel does
This gives us the central idea behind a theorem prover.
Proving a theorem means constructing a term of the required type, and verifying a proof means type checking that term.
The kernel does not reason about truth. It implements typing rules, which say when a term has a type, and it mechanically checks that a given term has a given type under those rules. Whether that counts as proof checking depends on whether the typing rules faithfully implement a logic, which is the subject of Chapter 4. Whether the rules are sound, so that no term inhabits the type of a false proposition, is the subject of Chapter 13 and Chapter 14.
This division of labour shapes the design of every serious prover: tactics, automation, decision procedures, and even a large language model may search for proofs and may contain bugs, because the kernel checks the term they produce. Only the kernel must be correct, so the goal is to keep it small. The kernel in this book is under fifteen hundred lines of Rust, comments included.
The plan
The chapters of Part I build the kernel for a type theory that is just large enough to serve as a logic.
- Chapter 2 fixes the language: universes, variables, -types, -abstractions, and application.
- Chapter 3 gives the typing rules, one per kind of term plus one that lets computation happen inside types.
- Chapter 4 shows that these rules are the rules of a logic, and defines consistency.
- Chapter 5 turns the rules into an algorithm and matches it against the Rust implementation.
- Chapter 6 runs the algorithm by hand on correct proofs, incorrect proofs, and proofs that need computation.
Two operations are deliberately treated as black boxes until Part III: substitution and definitional equality. Both are easy to state and easy to get wrong, and the kernel's correctness depends on them.
What to remember
- Propositions are types; proofs are terms; means that proves .
- Implication is the function type. Using a hypothesis is applying a function.
- Universal quantification is the dependent function type .
- A theorem prover's kernel is a type checker. Everything else only produces terms for it to check.