Typing rules

The underlying formal language of Coq is a Calculus of Inductive Constructions (CIC) whose inference rules are presented in this chapter. The history of this formalism as well as pointers to related work are provided in a separate chapter; see Early history of Coq.

The terms

The expressions of the CIC are terms and all terms have a type. There are types for functions (or programs), there are atomic types (especially datatypes)... but also types for proofs and types for the types themselves. Especially, any object handled in the formalism must belong to a type. For instance, universal quantification is relative to a type and takes the form “for all x of type T, P”. The expression “x of type T” is written “x:T”. Informally, “x:T” can be thought as “x belongs to T”.

Terms are built from sorts, variables, constants, abstractions, applications, local definitions, and products. From a syntactic point of view, types cannot be distinguished from terms, except that they cannot start by an abstraction or a constructor. More precisely the language of the Calculus of Inductive Constructions is built from the following rules.

  1. the sorts SProp, Prop, Set, Type(i) are terms.

  2. variables, hereafter ranged over by letters x, y, etc., are terms

  3. constants, hereafter ranged over by letters c, d, etc., are terms.

  4. if x is a variable and T, U are terms then x:T, U (forall x:T, U in Coq concrete syntax) is a term. If x occurs in U, x:T, U reads as “for all x of type T, U”. As U depends on x, one says that x:T, U is a dependent product. If x does not occur in U then x:T, U reads as “if T then U”. A non-dependent product can be written: TU.

  5. if x is a variable and T, u are terms then λx:T. u (fun x:T => u in Coq concrete syntax) is a term. This is a notation for the λ-abstraction of λ-calculus [Bar81]. The term λx:T. u is a function which maps elements of T to the expression u.

  6. if t and u are terms then (t u) is a term (t u in Coq concrete syntax). The term (t u) reads as “t applied to u”.

  7. if x is a variable, and t, T and u are terms then let x:=t:T in u is a term which denotes the term u where the variable x is locally bound to t of type T. This stands for the common “let-in” construction of functional programs such as ML or Scheme.

Free variables. The notion of free variables is defined as usual. In the expressions λx:T. U and x:T, U the occurrences of x in U are bound.

Substitution. The notion of substituting a term t to free occurrences of a variable x in a term u is defined as usual. The resulting term is written u{x/t}.

The logical vs programming readings. The constructions of the CIC can be used to express both logical and programming notions, according to the Curry-Howard correspondence between proofs and programs, and between propositions and types [CFC58][How80][dB72].

For instance, let us assume that nat is the type of natural numbers with zero element written 0 and that True is the always true proposition. Then is used both to denote natnat which is the type of functions from nat to nat, to denote True→True which is an implicative proposition, to denote natProp which is the type of unary predicates over the natural numbers, etc.

Let us assume that mult is a function of type natnatnat and eqnat a predicate of type natnatProp. The λ-abstraction can serve to build “ordinary” functions as in λx:nat. (mult x x) (i.e. fun x:nat => mult x x in Coq notation) but may build also predicates over the natural numbers. For instance λx:nat. (eqnat x 0) (i.e. fun x:nat => eqnat x 0 in Coq notation) will represent the predicate of one variable x which asserts the equality of x with 0. This predicate has type natProp and it can be applied to any expression of type nat, say t, to give an object P t of type Prop, namely a proposition.

Furthermore forall x:nat, P x will represent the type of functions which associate with each natural number n an object of type (P n) and consequently represent the type of proofs of the formula “x. P(x)”.

Typing rules

As objects of type theory, terms are subjected to type discipline. The well typing of a term depends on a local context and a global environment.

Local context. A local context is an ordered list of declarations of variables. The declaration of a variable x is either an assumption, written x:T (where T is a type) or a definition, written x:=t:T. Local contexts are written in brackets, for example [x:T; y:=u:U; z:V]. The variables declared in a local context must be distinct. If Γ is a local context that declares x, we write xΓ. Writing (x:T)Γ means there is an assumption or a definition giving the type T to x in Γ. If Γ defines x:=t:T, we also write (x:=t:T)Γ. For the rest of the chapter, Γ::(y:T) denotes the local context Γ enriched with the local assumption y:T. Similarly, Γ::(y:=t:T) denotes the local context Γ enriched with the local definition (y:=t:T). The notation [] denotes the empty local context. Writing Γ1;Γ2 means concatenation of the local context Γ1 and the local context Γ2.

Global environment. A global environment is an ordered list of declarations. Global declarations are either assumptions, definitions or declarations of inductive objects. Inductive objects declare both constructors and inductive or coinductive types (see Section Theory of inductive definitions).

In the global environment, assumptions are written as (c:T), indicating that c is of the type T. Definitions are written as c:=t:T, indicating that c has the value t and type T. We shall call such names constants. For the rest of the chapter, the E; c:T denotes the global environment E enriched with the assumption c:T. Similarly, E; c:=t:T denotes the global environment E enriched with the definition (c:=t:T).

The rules for inductive definitions (see Section Theory of inductive definitions) have to be considered as assumption rules in which the following definitions apply: if the name c is declared in E, we write cE and if c:T or c:=t:T is declared in E, we write (c:T)E.

Typing rules. In the following, we define simultaneously two judgments. The first one E[Γ]t:T means the term t is well-typed and has type T in the global environment E and local context Γ. The second judgment WF(E)[Γ] means that the global environment E is well-formed and the local context Γ is a valid local context in this global environment.

A term t is well typed in a global environment E iff there exists a local context Γ and a term T such that the judgment E[Γ]t:T can be derived from the following rules.

W-Empty
WF([])[]
W-Local-Assum
E[Γ]T:ssSxΓWF(E)[Γ::(x:T)]
W-Local-Def
E[Γ]t:TxΓWF(E)[Γ::(x:=t:T)]
W-Global-Assum
E[]T:ssScEWF(E; c:T)[]
W-Global-Def
E[]t:TcEWF(E; c:=t:T)[]
Ax-SProp
WF(E)[Γ]E[Γ]SProp:Type(1)
Ax-Prop
WF(E)[Γ]E[Γ]Prop:Type(1)
Ax-Set
WF(E)[Γ]E[Γ]Set:Type(1)
Ax-Type
WF(E)[Γ]E[Γ]Type(i):Type(i+1)
Var
WF(E)[Γ](x:T)Γ  or  (x:=t:T)Γ for some tE[Γ]x:T
Const
WF(E)[Γ](c:T)E  or  (c:=t:T)E for some tE[Γ]c:T
Prod-SProp
E[Γ]T:ssSE[Γ::(x:T)]U:SPropE[Γ] x:T,U:SProp
Prod-Prop
E[Γ]T:ssSE[Γ::(x:T)]U:PropE[Γ]x:T, U:Prop
Prod-Set
E[Γ]T:ss{SProp,Prop,Set}E[Γ::(x:T)]U:SetE[Γ]x:T, U:Set
Prod-Type
E[Γ]T:ss{SProp,Type(i)}E[Γ::(x:T)]U:Type(i)E[Γ]x:T, U:Type(i)
Lam
E[Γ]x:T, U:sE[Γ::(x:T)]t:UE[Γ]λx:T.t:x:T, U
App
E[Γ]t:x:U, TE[Γ]u:UE[Γ](t u):T{x/u}
Let
E[Γ]t:TE[Γ::(x:=t:T)]u:UE[Γ]let x:=t:T in u:U{x/t}

Note

Prod-Prop and Prod-Set typing-rules make sense if we consider the semantic difference between Prop and Set:

  • All values of a type that has a sort Set are extractable.

  • No values of a type that has a sort Prop are extractable.

Note

We may have let x:=t:T in u well-typed without having ((λx:T. u) t) well-typed (where T is a type of t). This is because the value t associated with x may be used in a conversion rule (see Section Conversion rules).

Subtyping rules

At the moment, we did not take into account one rule between universes which says that any term in a universe of index i is also a term in the universe of index i+1 (this is the cumulativity rule of CIC). This property extends the equivalence relation of convertibility into a subtyping relation inductively defined by:

  1. if E[Γ]t=βδιζηu then E[Γ]tβδιζηu,

  2. if ij then E[Γ]Type(i)βδιζηType(j),

  3. for any i, E[Γ]SetβδιζηType(i),

  4. E[Γ]PropβδιζηSet, hence, by transitivity, E[Γ]PropβδιζηType(i), for any i (note: SProp is not related by cumulativity to any other term)

  5. if E[Γ]T=βδιζηU and E[Γ::(x:T)]TβδιζηU then E[Γ]x:T, Tβδιζηx:U, U.

  6. if Ind [p](ΓI := ΓC) is a universe polymorphic and cumulative (see Chapter Polymorphic Universes) inductive type (see below) and (t:ΓP,ΓArr(t),S)ΓI and (t:ΓP,ΓArr(t),S)ΓI are two different instances of the same inductive type (differing only in universe levels) with constructors

    [c1:ΓP,T1,1T1,n1, t v1,1v1,m; ; ck:ΓP,Tk,1Tk,nk, t vk,1vk,m]

    and

    [c1:ΓP,T1,1T1,n1, t v1,1v1,m; ; ck:ΓP,Tk,1Tk,nk, t vk,1vk,m]

    respectively then

    E[Γ]t w1wmβδιζηt w1wm

    (notice that t and t are both fully applied, i.e., they have a sort as a type) if

    E[Γ]wi=βδιζηwi

    for 1im and we have

    E[Γ]Ti,jβδιζηTi,j

    and

    E[Γ]AiβδιζηAi

    where ΓArr(t)=[a1:A1; ; al:Al] and ΓArr(t)=[a1:A1; ; al:Al].

The conversion rule up to subtyping is now exactly:

Conv
E[Γ]U:sE[Γ]t:TE[Γ]TβδιζηUE[Γ]t:U

Normal form. A term which cannot be any more reduced is said to be in normal form. There are several ways (or strategies) to apply the reduction rules. Among them, we have to mention the head reduction which will play an important role (see Chapter Tactics). Any term t can be written as λx1:T1. λxk:Tk. (t0 t1tn) where t0 is not an application. We say then that t0 is the head of t. If we assume that t0 is λx:T. u0 then one step of β-head reduction of t is:

λx1:T1. λxk:Tk. (λx:T. u0 t1tn)  λ(x1:T1)(xk:Tk). (u0{x/t1} t2tn)

Iterating the process of head reduction until the head of the reduced term is no more an abstraction leads to the β-head normal form of t:

tλx1:T1. λxk:Tk. (v u1um)

where v is not an abstraction (nor an application). Note that the head normal form must not be confused with the normal form since some ui can be reducible. Similar notions of head-normal forms involving δ, ι and ζ reductions or any combination of those can also be defined.

The Calculus of Inductive Constructions with impredicative Set

Coq can be used as a type checker for the Calculus of Inductive Constructions with an impredicative sort Set by using the compiler option -impredicative-set. For example, using the ordinary coqtop command, the following is rejected,

Example

Fail Definition id: Set := forall X:Set,X->X.
The command has indeed failed with message: The term "forall X : Set, X -> X" has type "Type" while it is expected to have type "Set" (universe inconsistency: Cannot enforce Set+1 <= Set).

while it will type check, if one uses instead the coqtop -impredicative-set option..

The major change in the theory concerns the rule for product formation in the sort Set, which is extended to a domain in any sort:

ProdImp
E[Γ]T:ssSE[Γ::(x:T)]U:SetE[Γ]x:T, U:Set

This extension has consequences on the inductive definitions which are allowed. In the impredicative system, one can build so-called large inductive definitions like the example of second-order existential quantifier (exSet).

There should be restrictions on the eliminations which can be performed on such definitions. The elimination rules in the impredicative system for sort Set become:

Set1
s{Prop,Set}[I:Set|Is]
Set2
I is a small inductive definitions{Type(i)}[I:Set|Is]