In mathematics, logic, and computer science, a type theory is a formal system in which every "term" has a "type". A "type" in type theory has a role similar to a "type" in a programming language: it dictates the operations that can be performed on a term and, for variables, the possible values it might be replaced with.
Some type theories serve as alternatives to set theory as a foundation of mathematics. Two influential type theories that were proposed as foundations are Alonzo Church's typed λ-calculus and Per Martin-Löf's intuitionistic type theory. Most computerized proof-writing systems use a type theory for their foundation. A common one is Thierry Coquand's Calculus of Inductive Constructions.
Type theory is closely related to, and in some cases overlaps with, type systems, which are a programming language feature used to reduce bugs and facilitate certain compiler optimizations. Because type theory and type systems can overlap, some experts use the phrase "type system" to refer to a specific formal system and the phrase "type theory" to refer to the academic study of them.
Type theory was created to avoid a paradox in a mathematical foundation based on naive set theory and formal logic. Russell's paradox, which was discovered by Bertrand Russell, existed because a set could be defined using "all possible sets", which included itself. Between 1902 and 1908, Bertrand Russell proposed various "theories of type" to fix the problem. By 1908 Russell arrived at a "ramified" theory of types together with an "axiom of reducibility" both of which featured prominently in Whitehead and Russell's Principia Mathematica published between 1910 and 1913. This system avoided Russell's paradox by creating a hierarchy of types and then assigning each concrete mathematical (and possibly other) entity to a type. Entities of a given type are built exclusively from entities of those types that are lower in their hierarchy, thus preventing an entity from being defined using itself.
The most famous early example is Church's simply typed lambda calculus. Church's theory of types helped the formal system avoid the Kleene–Rosser paradox that afflicted the original untyped lambda calculus. Church demonstrated that it could serve as a foundation of mathematics and it was referred to as a higher-order logic.
The phrase "type theory" now generally refers to a typed system based around lambda calculus. One influential system is Per Martin-Löf's intuitionistic type theory, which was proposed as a foundation for constructive mathematics. Another is Thierry Coquand's calculus of constructions, which is used as the foundation by Coq, Lean, and other "proof assistants" (computerized proof writing programs). Type theories are an area of active research, as demonstrated by homotopy type theory.
There are many type theories, so describing them all is difficult. This section covers features of many major type theories. It is an introduction for those unfamiliar with type theory. This section is not trying to be a complete categorization of type theories, nor an exhaustive description of them.
Terms can be built out of other terms using function calls. In type theory, a function call is called "function application". Function application takes a term of a given type and results in a term of another given type. Function application is written "function argument argument ...", instead of the conventional "function(argument,argument, ...)". For natural numbers, it is possible to define a function called "add" that takes two natural numbers. Thus, some more terms with their types are:
Terms may also contain variables. Variables always have a type. So, assuming "x" and "y" are variables of type "nat", the following are also valid terms:
There are more types than "nat" and "bool". We have already seen the term "add", which is not a "nat", but a function that, when applied to two "nat"s, computes to a "nat". The type of "add" will be covered later. First, we need to describe "computes to".
Type theory has a built-in notation of computation. The following terms are all different:
Terms that contain variables can be reduced too. So the term "x + (1 + 4) : nat" reduces to "x + 5 : nat". (We can reduce any sub-term within a term, thanks to the Church-Rosser theorem.)
A term without any variables that cannot be reduced further is a "canonical term". All the terms above reduce to "5 : nat", which is a canonical term. The canonical terms of the natural numbers are:
Obviously, terms that compute to the same term are equal. So, assuming "x : nat", the terms "x + (1 + 4) : nat" and "x + (4 + 1) : nat" are equal because they both reduce to "x + 5 : nat". When two terms are equal, they can be substituted for each other. Equality is a complex topic in type theory and there are many kinds of equality. This kind of equality, where two terms compute to the same term, is called "judgemental equality".
In type theory, functions are terms. Functions can either be lambda terms or defined "by rule".
An example of a lambda term is this function which doubles its argument:
Earlier, we saw that function application is written by putting the parameter after the function term. So, if we want to call the above function with the parameter "5" of type "nat", we write:
A lambda term is often called an "anonymous function" because it has no name. Often, to make things easier to read, a name is given to a lambda term. This is merely a notation and has no mathematical meaning. Some authors call it "notational equality". A name might be given to the function above using the notation:
This is the same function as above, just a different way to write it. So the term
Dependent typing is when the type returned by a function depends on the value of its argument. For example, when a type theory has a rule that defines the type "bool", it also defines the function "if". The function "if" takes 3 arguments and "if true b c" computes to "b" and "if false b c" computes to "c". But what is the type of "if a b c"?
If "b" and "c" have the same type, it is obvious: "if a b c" has the same type as "b" and "c". Thus, assuming "a : bool",
But if "b" and "c" have different types, then the type of "if a b c" depends on the value of "a". We use the symbol "Π" to indicate a function that takes an argument and returns a type. Assuming we have some types "B" and C" and "a : bool", "b : B" and "c : C", then
That is, the type of the "if" term is either the type of the second or third argument, depending on the value of the first argument. In actuality, "if a B C" isn't defined using "if", but that gets into details too complicated for this introduction.
Universes are complicated. If a universe contains itself, it can lead to paradoxes like Girard's Paradox. The details of universes are too long and complicated for this introduction.
Type theories are defined by their rules of inference. There are rules for a "functional core", described above, and rules that create types and terms. Below is a non-exhaustive list of common types and their associated terms.
The list ends with "inductive types", which is a powerful technique that is able to construct all the other ones in the list. The mathematical foundations used by the proof assistants "Coq" and "Lean" are based on the "Calculus for Inductive Constructions" which is the "Calculus of Constructions" (its "functional core") with inductive types.
The Boolean type is defined with an eliminator function "if" such that:
The identity type is the third concept of equality in type theory. The first is "notational equality", which is for definitions like "2 : nat ::= (S (S 0))" that have no mathematical meaning but are useful to readers. The second is "judgemental equality", which is when two terms compute to the same term, like "x + (1 + 4)" and "x + (4 + 1)", which both compute to "x + 5". But type theory needs another form of equality, known as the "identity type" or "propositional equality".
The reason it needs the identity type is because some equal terms do not compute to the same term. Assuming "x : nat", the terms "x + 1" and "1 + x" do not compute to the same term. Recall that "+" is a notation for the function "add", which is a notation for the function "R". We cannot compute on "R" until the value for "x" is specified and, until it is specified, two different calls to "R" will not compute to the same term.
An identity type requires two terms "a" and "b" of the same type and is written "a = b". So, for "x + 1" and "1 + x", the type would be "x+1 = 1+x". Canonical terms are created with the constructor "reflexivity". The call "reflexivity a" takes a term "a" and returns a canonical term of the type "a = a".
Computation with the identity type is done with the eliminator function "J". The function "J" lets a term dependent on "a", "b", and a term of type "a = b" to be rewritten so that "b" is replaced by "a". While "J" is one directional, only able to substitute "b" with "a", it can be proven that the identity type is reflexive, symmetric and transitive.
To be clear, it is possible to create the type "0 = 1", but there will not be a way to create terms of that type. Without a term of type "0 = 1", it will not be possible to use the function "J" to substitute "0" for "1" in another term.
The complexities of equality in type theory make it an active research area, see homotopy type theory.
Inductive types is a way to create a large variety of types. In fact, all the types described above and more can be defined using the rules of inductive types. Once the type's constructors are specified, the eliminator functions and computation is determined by structural recursion.
There are similar, more powerful ways to create types. These include induction-recursion and induction-induction. There is also a way to create similar types using only lambda terms, called Scott encoding.
(NOTE: Type theories do not usually include coinductive types. They represent an infinite data type and most type theories limit themselves to functions that can be proven to halt.)
The traditional foundation for mathematics has been set theory paired with a logic. The most common one cited is Zermelo–Fraenkel set theory, known as "ZF" or, with the Axiom of choice, "ZFC". Type theories differ from this foundation in a number of ways.
Proponents of type theory will also point out its connection to constructive mathematics through the BHK interpretation, its connected to logic by the Curry–Howard isomorphism, and its connections to Category theory.
A term in logic is recursively defined as a constant symbol, variable, or a function application, where a term is applied to another term. Some constant symbols will be "0" of the natural numbers, "true" of the Booleans, and functions like "S" and "if". Thus some terms are "0", "(S 0)", "(S (S x))", and "if true 0 (S 0)".
If there are no assumptions, there will be nothing to the left of the turnstile.
(NOTE: The judgement of equality of terms is where the phrase "judgemental equality" comes from. )
The judgements enforce that every term has a type. The type will restrict which rules can be applied to a term.
A type theory's rules say what judgements can be made, based on the existence of other judgements. The rules are expressed using a horizontal line, with the required input judgements above the line and the resulting judgement below the line. The rule for creating a lambda term is:
To generate a particular judgement in type theory, there must be a rule to generate it. Then, there must be rules to generate all of that rule's required inputs. And then rules for all the inputs for those rules. The applied rules form a proof tree. This is usually drawn Gentzen-style, where the target judgement (root) is at the bottom and rules that do not require any inputs (leaves) at the top. (See Natural deduction#Proofs_and_type_theory.) An example of a rule that does not require any inputs is one that states there is a term "0" of type "nat":
Terms usually belong to a single type. However, there are set theories that define "subtyping".
Computation takes place by repeated application of rules. Many type theories are strongly normalizing, which means that any order of applying the rules will always end in the same result. However, some are not. In a normalizing type theory, the one-directional computation rules are called "reduction rules" and applying the rules "reduces" the term. If a rule is not one-directional, it is called a "conversion rule".
Most type theories do not have axioms. This is because a type theory is defined by its rules of inference. (See "Rules" above). This is a source of confusion for people familiar with Set Theory, where a theory is defined by both the rules of inference for a logic (such as first-order logic) and axioms about sets.
Sometimes, a type theory will add a few axioms. An axiom is a judgement that is accepted without a derivation using the rules of inference. They are often added to ensure properties that cannot be added cleanly through the rules.
The Axiom of Choice does not need to be added to type theory, because in most type theories it can be derived from the rules of inference. This is because of the constructive nature of type theory, where proving that a value exists requires a method to compute the value. The Axiom of Choice is less powerful in type theory than most set theories, because type theory's functions must be computable and, being syntax-driven, the number of terms in a type must be countable. (See Axiom of choice § In constructive mathematics.)
Girard's paradox shows that type inhabitation is strongly related to the consistency of a type system with Curry–Howard correspondence. To be sound, such a system must have uninhabited types.
The opposition of terms and types can also be views as one of implementation and specification. By program synthesis (the computational counterpart of) type inhabitation (see below) can be used to construct (all or parts of) programs from specification given in form of type information.
Many programs that work with type theory (e.g., interactive theorem provers) also do type inferencing. It lets them select the rules that the user intends, with fewer actions by the user.
Homotopy type theory differs from intuitionistic type theory mostly by its handling of the equality type. In 2016 cubical type theory was proposed, which is a homotopy type theory with normalization.
Type theory has connections to other areas of mathematics. Proponents of type theory as a foundation often mention these connections as justification for its use.
When used as a foundation, certain types are interpreted as propositions (statements that can be proven) and a term of the type is a proof of that proposition. Thus, the type "Π x:nat . x+1=1+x" represents that, for any "x" of type "nat", "x+1" and "1+x" are equal. And a term of that type represents its proof.
When some types are interpreted as propositions, there is a set of common types that can be used to connect them to make a logic out of types. However, that logic is not classical logic but intuitionistic logic. That is, it does not have the law of excluded middle nor double negation.WARNING: This interpretation can lead to a lot of confusion. A type theory may have "true" and "false" of type "bool", which act like a Boolean logic, and at the same time have
Under this intuitionistic interpretation, there are common types that act as the logical operators:
Thus, the logic-of-types is an intuitionistic logic. Type theory is often cited as an implementation of the Brouwer–Heyting–Kolmogorov interpretation.
It is possible to include the law of excluded middle and double negation into a type theory, by rule or assumption. However, terms may not compute down to canonical terms and it will interfere with the ability to determine if two terms are judgementally equal to each other.
Constructive mathematics has often used intutionistic logic, as evidenced by the Brouwer–Heyting–Kolmogorov interpretation.
Most of the type theories proposed as foundations are constructive. This includes most of the ones used by proof assistants.
It is possible to add non-constructive features to a type theory, by rule or assumption. These include operators on continuations such as call with current continuation. However, these operators tend to break desirable properties such as canonicity and parametricity.
Although the initial motivation for category theory was far removed from foundationalism, the two fields turned out to have deep connections. As John Lane Bell writes: "In fact categories can themselves be viewed as type theories of a certain kind; this fact alone indicates that type theory is much more closely related to category theory than it is to set theory." In brief, a category can be viewed as a type theory by regarding its objects as types (or sorts), i.e. "Roughly speaking, a category may be thought of as a type theory shorn of its syntax." A number of significant results follow in this way:
The interplay, known as categorical logic, has been a subject of active research since then; see the monograph of Jacobs (1999) for instance.
Homotopy type theory attempts to combine type theory and category theory. It focuses on equalities, especially equalities between types.
The first computer proof assistant, called Automath, used type theory to encode mathematics on a computer. Martin-Löf specifically developed intuitionistic type theory to encode all mathematics to serve as a new foundation for mathematics. There is ongoing research into mathematical foundations using homotopy type theory.
Mathematicians working in category theory already had difficulty working with the widely accepted foundation of Zermelo–Fraenkel set theory. This led to proposals such as Lawvere's Elementary Theory of the Category of Sets (ETCS). Homotopy type theory continues in this line using type theory. Researchers are exploring connections between dependent types (especially the identity type) and algebraic topology (specifically homotopy).
Much of the current research into type theory is driven by proof checkers, interactive proof assistants, and automated theorem provers. Most of these systems use a type theory as the mathematical foundation for encoding proofs, which is not surprising, given the close connection between type theory and programming languages:
There is extensive overlap and interaction between the fields of type theory and type systems. Type systems are a programming language feature designed to identify bugs. Any static program analysis, such as the type checking algorithms in the semantic analysis phase of compiler, has a connection to type theory.
A prime example is Agda, a programming language which uses UTT (Luo's Unified Theory of dependent Types) for its type system. The programming language ML was developed for manipulating type theories (see LCF) and its own type system was heavily influenced by them.
Type theory is also widely used in formal theories of semantics of natural languages, especially Montague grammar and its descendants. In particular, categorial grammars and pregroup grammars extensively use type constructors to define the types (noun, verb, etc.) of words.