When shopping for a dependent type theory, many factors should be taken into consideration: how inductive data is represented (inductive schemas vs W-types), how inductive data computes (eliminators vs case trees), how types of types are represented (universes à la Tarski vs à la Russell). However, the most important is their treatment of equality.
Conor McBride, a prominent figure in type theory research, noted in a reddit comment that you should never trust a type theorist who has not changed their mind about equality (I’m paraphrasing). Recently, I’ve embarked on a journey to improve my credibility (or, at least, get out of the “instantly discarded opinion” pool): I’ve changed my mind about equality.
What’s the fuss about?
Equality is very prevalent when using dependently typed languages, whether as frameworks for writing mathematical proofs or for writing verified computer programs. Most properties of mathematical operators are expressed as equalities which they should respect. For example, a semigroup is a set with an associative operator. The property of associativity just means the operator respects the equality !
However, the equality relation which can be expressed with proofs is not the only equality which a dependently-typed system needs to consider. There’s also the judgemental equality, that is, which terms are always identified independently of their semantics. For example, and are propositionally equal, which can be shown by writing an inductive proof of this fact, but they’re judgmentally different, because they have different term structure.
There are two ‘main’ traditions of Martin-Löf dependent type theory: the intensional type theories are as in the paragraph above, but the extensional type theories make me a liar. Extensional type theory is obtained by adding a rule of equality reflection, which collapses the distinction between propositional and judgemental equality: whenever there exists a proof of an equality between terms and , they’re considered judgmentally equal.
Adding equality reflection makes a type system more expressive with respect to equality: for example, in extensional type theories, one can derive the rule of function extensionality, which says two functions are equal when they are equal pointwise. However, equality reflection also makes a type system less expressive with respect to equality: there is only one way for two things to be equal!
Moreover, equality reflection complicates type checking to an unacceptable degree. Rather than being able to check the validity of a proof by comparing a term against a known type, an entire typing derivation is necessary as input to the type checker. To see why, consider the following derivation:
Here, the context contains an element of the empty type, written . It’s comparatively easy for the type checker to see that in this case, the context we’re working under is absurd, and any equality should be accepted. However, there are many such empty types: , for example. Consider the type family , indexed by a Boolean clause, such that reduces to when is satisfiable and otherwise. How would you type-check the program at type , where is some adversarially-chosen, arbitrarily complex expression? How would you type check it at type ?
In contrast, Intensional Type Theory, or ITT for short, treats equality as if it were any other type. In ITT, equality is inductively generated by the constructor for any element of a type , which leads to an induction principle saying that, if
- is a type, and
- is a proposition indexed by and , and
- is a proof of , then
we can deduce, for all and , that holds.
Given this operator, generally called axiom J (since “J” is the letter after Identity, another word for “equality”), we can derive many of the properties of equality: transitivity (given and , get ) and symmetry (given , get ) make an equivalence relation, and substitutivity (assuming and , get ) justifies calling it “equality”.
However, axiom J is both weaker and stronger than equality reflection: for one, it doesn’t let us prove that functions are equal when they are pointwise equal, which leads to several complications. However, it also doesn’t let us prove that all equalities are equal to , which lets us strengthen equality by postulating, for example,
The univalence axiom of Voevodsky
The “tagline” for the univalence axiom, which lies at the center of Homotopy Type Theory (HoTT), is that “equality is equivalent to equivalence”. More specifically, given a function , together with a proof that has left and right inverses, univalence gives us an equality such that transporting “along” this path is the same as applying .
For example, we could define the “usual” unary naturals (which are easy to use for proving but terrible computationally) and binary naturals (which have more efficient computational behaviour at the cost of more complicated structure), demonstrate an equivalence , then transport proofs about to proofs about !
A recent paper by Tabareau et al explores the consequences of strengthening a type theory with univalence together with parametricity, unlocking efficient and automated (given the equivalence) transport between algebraic structures of types.
Using the “path” terminology in a context with unicity of equality proofs is a bit misleading, but the terminology does not break down (a set-truncated system is just one where all paths are loops). Because of this, I’ll use “path” and “equality” interchangeably. Sorry if this causes any confusion.
A note on terminology The HoTT interpretation of “types as topological spaces” leads us to interpret the type of equalities as the type of paths in a space. From this, we get some terminology: instead of saying “cast with the equality ”, we can equivalently say “transport along the path ”.
The undecidability of type checking ETT and the comparative weakness of ITT has led many researchers to consider the following question:
Can we have:
- Decidable type checking
- A “more extensional” equality
- Good computational behaviour
All at the same time?
Turns out, the answer is yes!
One early positive answer is that of Observational Type Theory, presented in a 2007 paper by Altenkirch, McBride, and Swierstra. The basic idea is that, instead of defining the type as an inductive family of types, we define it so that equality computes on the structure of , and to reduce to tractable forms. Observational type theory (OTT, from now on) has two universes (types whose elements are types), and , such that and 1
The elements of are taken to be propositions, not in the sense of propositions-as-types, but in the sense of HoTT. Propositions are the types for which, given , one has : they’re types with at most one element. Some propositions are , the trivially true proposition, and , the empty proposition.
Given , and some with one variable free (where and are possibly distinct universes), we can form the type of dependent products from to . If is in , then the dependent product also lives in . Otherwise, it lives in . Moreover, we can also form the type of dependent sums of and , which always lives in .
Given a type and two elements , we can form the proposition . Note the emphasis on the word proposition here! Since equivalence is a proposition, we have uniqueness of equality proofs by definition: there’s at most one way for things to be equal, conflicting with univalence. So we get some extensionality, namely of functions, but not for arbitrary types. Given types and , a proof and , we have the term , which represents the coercion of along the path .
Here is where my presentation of observational equality starts to differentiate from the paper’s: McBride et al use heterogeneous equality, i.e. a 4-place relation , where and are potentially distinct types. But! Their system only allows you to use an equality when . The main motivation for heterogeneous equality is to “bunch up” as many equalities as possible to be eliminated all in one go, since coercion in their system does not compute. However, if coercion computes normally, then we don’t need to do this “bunching”: one can just use coercion normally.
The key idea of OTT is to identify as “equal” objects which support the same observations: for functions, observation is application; for pairs, it’s projection, etc. This is achieved by making the definition of equality acts as a “pattern matching function” on the structure of terms and types. For example, there is a rule which says an equality between functions is a function that returns equalities:
So, not only do we have a term
funext of type
((x : A) → f x == g x) → f == g but one with a stronger type, namely
((x : A) → f x == g x) == (f == g), and that term is..
OTT is appropriate, in my opinion, for doing set-level mathematics: where types have no “interesting” equality structure. However, it breaks down at higher h-levels, where there is interesting structure to be found in the equalities between elements of types. This is because OTT, by placing the type in its universe of propositions, validates the principle of uniqueness of identity proofs, which says any two proofs of the same equality are themselves equal. UIP conflicts with the univalence axiom of Homotopy Type Theory, by (to use the HoTT terminology) saying that all types are sets.
Theorem. Suppose there exists one universe, , which contains the type of Booleans. Assuming univalence, the type is not a proposition.
Proof. The function , which maps to and vice-versa, is an equivalence, being its own left and right inverses. Thus, by univalence, we have a path .
To see that this path is different from , consider its behaviour with respect to transport: but . Since is different from , it follows that is different from .
So, if having univalence is desirable, OTT is off the table. However, the previous example of transporting proofs between equivalent types of natural numbers might not have convinced you that HoTT is indeed an interesting field of study, and univalence might seem mostly like a novelty, a shiny thing to pursue for its own sake (it certainly did to me, at first). So why is HoTT interesting?
Between 2012 and 2013, a special year of research took place in the Institute for Advanced Studies to develop a type theory that can be used as a foundation for mathematics “at large”. Their result: the book Homotopy Type Theory: Univalent Foundations for Mathematics. The IAS Special Year on Univalent Foundations would have been interesting even if it hadn’t started a new branch of type theory, just from the participants: Thierry Coquand, Thorsten Altenkirch, Andrej Bauer, Per Martin-Löf and, of course, the late Vladimir Voevodsky.
HoTT’s main contribution to the field, in my (lay) opinion, is the interpretation of types as spaces: by interpreting types as homotopy theoretical spaces, a semantics for types with more interesting “equality structure”, so to speak, arises. In the “classical” intensional type theory of Agda and friends, and indeed the theory of OTT commented on above, equality is a proposition. Agda (without the
--without-K option) accepts the following proof:
: (A : Set) (x y : A) (p q : x ≡ y) → p ≡ q uip .x refl refl = refluip A x
Apart from ruling out univalence, UIP rules out another very interesting class of types which can be found in HoTT: the higher inductive types, which contain constructors for equalities as well as for values.
The simplest higher inductive type is the interval, which has two “endpoints” (
i1) and a path between them:
data I : Type where : I i0 i1 : i0 ≡ i1 seg
The names , and were chosen to remind the reader of a line segment between a pair of points. Therefore, we may represent the type as a diagram, with discrete points representing and , and a line, labelled , connecting them.
The real power of the
I type comes from its induction principle, which says that, given a proposition , if:
- There exists a pair of proofs and , and
- and are equal “with respect to” the path , then
holds for every element of the interval. However, that second constraint, which relates the two proofs, needs a bit of explaining. What does it mean for two elements to be equal with respect to a path? Well, the “obvious” interpretation would be that we require a proof . However, this isn’t well-typed! The type of is and the type of is , so we need a way to make them equal.
This is where the path comes in to save the day. Since it states and are equal, we can transport the proof along the path to get an inhabitant of the type , which makes our desired equality between with respect to come out as , which is well-typed.
That’s fine, I hear you say, but there is a question: how is the interval type useful? It certainly looks as though if it were useless, considering it’s just got one element pretending to be two! However, using the interval higher inductive type, we can actually prove functional extensionality, the principle that says two functions are equal when they’re equal pointwise, everywhere. The proof below can be found, in a more presentable manner, in the HoTT book, section 6.3.
Theorem. If and are two functions between and such that for all elements , then .
Proof. Call the proof we were given We define, for all , the function by induction on . Let , . The equality between these terms is given by .
Now, define by . We have that is the function , which is defined to be , which is -equal to . Similarly, is equal to , and thus, .
Isn’t that cool? By augmenting our inductive types with the ability to additionally specify equalities between elements, we get a proof of function extensionality! I think that’s pretty cool. Of course, if HITs were limited to structures like the interval, spheres, and other abstract mathematical things, they wouldn’t be very interesting for programmers. However, the ability to endow types with additional equalities is also useful when doing down-to-earth programming! A 2017 paper by Basold et al explores three applications of HITs to programming, in addition to containing an accessible introduction to HoTT in general.
Another very general higher inductive type, one that might be more obviously useful, is the general type of quotients. Whenever is a type and is a binary, propositional relation between members of , we can form the quotient type , which is given by the following constructors2:
- says that, for each , we can make an element of , and
- which gives, for each which are related by , an equality between and .
The induction principle for quotients, which is far too complicated to include here (but can be derived mechanically from the specification given above and the knowledge of “equal with respect to some path” from the section on the interval), says roughly that we can pattern-match on if and only the function we’re defining does not distinguish between elements related by .
This type is very general! For example, given a type of naturals and a two-place relation which holds for numbers congruent modulo 2, we can form the quotient type of naturals mod 2. Functions (say, ) defined on this type must then respect the relation that, whenever , .
All of this talk about HoTT, and in fact the book itself, though, neglected to mention one thing. What is the computational content of the univalence axiom? What are the reduction rules for matching on higher inductive types? How do we take a proof, written in the language of HoTT, and run it? The Book does not address this, and in fact, it’s still a half-open problem, and has been since 2013. Computing in the presence of all these paths, paths between paths, ad infinitum is mighty complicated.
The challenge of making a computational HoTT did not stop Cohen et al, who in a 2016 paper presented Cubical Type Theory, which, after three years of active research, provides a way to compute in the presence of univalence. There’s just one problem, though: cubical type theory is hella complicated.
The core idea is simple enough: we extend type theory with a set of names , with points and and operations , , and , which behave like a de Morgan algebra. To represent equalities, the type is introduced, together with a “name abstraction” operation and “path application” , where is an element of the interval.
The intuition, the authors say, is that a term with variables of -type free corresponds to an -dimensional cube.
This is about where anyone’s “intuition” for Cubical Type Theory, especially my own, flies out the window. Specifically, using abstraction and the de Morgan algebra on names, we can define operations such as reflexivity (), symmetry (), congruence, and even function extensionality, which has a delightfully simple proof: .
However, to transport along these paths, the paper defines a “face lattice”, which consists of constraints on elements of the interval, uses that to define “systems”, which are arbitrary restrictions of cubes; From systems, one can define “composition”, which compute the lid of an open box (yeah, I don’t get it either), “Kan filling”, and finally, transport. Since the authors give a semantics of Cubical Type Theory in a previously well-established model of cubical sets, I’ll just.. take their word on this.
The Cubical Agda documentation has a section explaining a generalised transport operation
transp and the regular transport operation
transport. I recommend that you go check that out, since explaining each is beyond my powers. However, this transport operation does let us prove that the J induction principle for equalities also holds for these cubical paths, and from that we can define all of the other nice operations!
Cubical Agda, a proof assistant based on Cubical Type Theory, exports a library which provides all of HoTT’s primitive notions (The identity type, transport, the J rule, function extensionality, univalence), that compute properly. Furthermore, it supports higher inductive types! However, as I understand it, these can not be compiled into an executable program yet. This is because the
transp operation, fundamental to computation in the presence of path types, is defined on the structure of the type we’re transporting over, and type structure is not preserved when compiling.
Even after all this explanation of fancy equality relations, you might still be unconvinced. I certainly was, for a while. But I’d argue that, if you care about typed programming enough to be interested in dependent types at all, you should be interested in, at least, the quotient inductive types of OTT, if not the more general higher inductive types of HoTT.
The reason for this is simple: inductive types let you restrict how elements of a type are formed. Quotient inductive types let you restrict, in a principled way, how elements of a type are used. Whereas in languages without quotients, like Haskell or even non-cubical Agda, one is forced to use the module system to hide the inductive structure of a type if they wish to prevent unauthorized fiddling with structure, in a language with quotients, we can have the type checker enforce, internally, that these invariants are maintained.
Just like quantitative type theory gives programmers a way to reason about resource usage, and efficiently implement mutable structures in a referentially-transparent way, I strongly believe that quotient types, and even univalent parametricity (when we figure out how to compile that) are the “next step forward” in writing reliable software using types as a verification method.
So I leave you, dear reader, with this question: what can we do, as researchers and implementors, to make dependently typed languages more user-friendly? If you are not a researcher, and you have tried a dependently typed language, what are pain points you have encountered? And if you haven’t used a dependently typed language, why not?
With special thanks to
This is a simplified presentation that uses a single, inconsistent universe (Girard’s paradox applies). The actual presentation uses a stratified, predicative hierarchy of universes to avoid this paradox.↩︎
The presentation of quotients in the HoTT book also contains a 0-truncation constructor, which has to do with limiting quotients to work on sets only. The details are, IMO, out of scope for this post; So check out section 6.10 of the book to get all of them.↩︎
Please read the italics on this paragraph as derision.↩︎