The Calculus of Constructions
Abstract
This post is part of a series on how to reason about code. It describes
- first, long-ago post here
- a concrete example of symbolic execution
- why I'm interested in type theory
- the λ Calculus
- the Simply Typed Lambda Calculus
This exposition follows that in "Type Theory & Formal Proof" by Nederpelt & Geuvers (abbreviated TTFP throughout), with help from "Lambda Calculi with Types" by Henk Barendregt. Also recommended is the post A Guide to Typed Lambda Calculus.
Recap
In this series, we've introduced the λ Calculus as a formal model of general computation & we've added a type system (
This post will bring those extensions together into a unified family of typed lambda calculii.
The λ Cube
In some sense,
provides terms depending on types, in that can only be used for computation after being applied to a type provides types depending on types, in that we can here build functions on types, such as provides types depending on terms in the form of dependent types
Therefore, they can be combined at will: we can imagine a type system that provides terms depending on types and types depending on types, for instance. Barendregt, in "Lambda Calculi with Types" showed that all eight combinations could be expressed within a single unified system of derivation rules and laid them out on the λ-Cube (also known as the Barendregt Cube)1:
Figure 1: The λ Cube
Here, the system
Here is the unified set of derivation rules for the
Note in particular the (form) rule– this is the heart of the matter. We're now letting the sorts of both the variable being abstracted over and the abstraction body vary independently. By limiting the range of each term in the formation rule in different ways, we obtain the eight different type systems in the λ Cube. The following table displays the eight type systems along with the permissible values for
system | ||||
---|---|---|---|---|
(∗,∗) | ||||
(∗,∗) | ||||
(∗,∗) | ||||
(∗,∗) | ||||
(∗,∗) | ||||
(∗,∗) | ||||
(∗,∗) | ||||
(∗,∗) |
Showing that the eight rules listed here reduce to those for each of the four type systems we've covered for appropriate choices of
It should be noted that this is in no way a complete accounting of the type systems that have been built on top of the λ Calculus. In particular, the λ Cube itself has been generalized to Pure Type Systems (PTS) which allow an arbitrary number of sorts.
The easiest way to conceptualize
Terms continue to be strongly normalizing. Well-typedness & type checking continue to be decidable, though term finding is undecidable (as it is everywhere outside
Unsurprisingly,
Where Are We?
I started this series of posts looking to understand Coq in terms of first principles. Since Coq is at heart a system for writing down terms in a certain formal language, I went back to the beginning: Church's λ Calculus. I worked from there in an exercise in the Feynman technique, and we're almost to Coq's formal language. Coq extends
It was only when we got to the last post that we were finally in a position to see exactly how "proof as term finding" actually worked, and I found myself wondering: why use type theory for this? I'm still not entirely clear, but it's undeniable that to date, the latter has been predominant in the development of proof assistants such as Coq.
Both approaches seem to date back to the early seventies; Mizar (which is based on set theory rather than type theory) dates back to 1973. Per TTFP: "The first system to actually use type theory to formalise mathematics was the Automath system, developed by N.G. de Bruijn and his research team in the early 1970s… There are various Automath type theories and several of them have been implemented as proof checkers."
The abovelinked MathOverflow question "What makes dependent type theory more suitable than set theory for proof assistants?" suggests that the real driver lies in the needs of the higher-level language that proof assistants use to define the mathematical objects about which the user is reasoning. This is generally known as the "vernacular", as opposed to the the smaller, simpler language used in the proof assistant kernel for proof checking. Because type theory can describe objects and sets with greater generality than set theory with predicate logic, the a proof assistant's vernacular almost has to be based on either type theory, or an extension to set theory with predicates that "looks a lot like type theory." At which point, "why bother with the set-theoretic kernel?"
Regardless, I think this post will wrap-up the series for a bit. A really complete treatment would show how we encode things like negation, conjunction & so forth in
05/28/24 18:30
Footnotes:
By Tellofou - Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=76344034