1.5 Product types

Given types A,B:𝒰 we introduce the type AΓ—B:𝒰, which we call their cartesian product. We also introduce a nullary product type, called the unit type 𝟏:𝒰. We intend the elements of AΓ—B to be pairs (a,b):AΓ—B, where a:A and b:B, and the only element of 𝟏 to be some particular object ⋆:𝟏. However, unlike in set theoryMathworldPlanetmath, where we define ordered pairsMathworldPlanetmath to be particular sets and then collect them all together into the cartesian product, in type theoryPlanetmathPlanetmath, ordered pairs are a primitive conceptMathworldPlanetmath, as are functions.

Remark 1.5.1.

There is a general pattern for introduction of a new kind of type in type theory, and because productsPlanetmathPlanetmath are our second example following this pattern,11The description of universesPlanetmathPlanetmath above is an exception. it is worth emphasizing the general form: To specify a type, we specify:

  1. 1.

    how to form new types of this kind, via formation rules. (For example, we can form the function type Aβ†’B when A is a type and when B is a type. We can form the dependent function type ∏(x:A)B⁒(x) when A is a type and B⁒(x) is a type for x:A.)

  2. 2.

    how to construct elements of that type. These are called the type’s constructors or introduction rules. (For example, a function type has one constructor, Ξ»-abstraction. Recall that a direct definition like f(x):≑2x can equivalently be phrased as a Ξ»-abstraction f:≑λx. 2x.)

  3. 3.

    how to use elements of that type. These are called the type’s eliminators or elimination rules. (For example, the function type has one eliminator, namely function application.)

  4. 4.

    a computation rule22also referred to as Ξ²-reductionPlanetmathPlanetmath, which expresses how an eliminator acts on a constructor. (For example, for functions, the computation rule states that (Ξ»x.Ξ¦)(a) is judgmentally equal to the substitution of a for x in Ξ¦.)

  5. 5.

    an optional uniqueness principle33also referred to as Ξ·-expansion, which expresses uniqueness of maps into or out of that type. For some types, the uniqueness principle characterizes maps into the type, by stating that every element of the type is uniquely determined by the results of applying eliminators to it, and can be reconstructed from those results by applying a constructorβ€”thus expressing how constructors act on eliminators, dually to the computation rule. (For example, for functions, the uniqueness principle says that any function f is judgmentally equal to the β€œexpanded” function λ⁒x.f⁒(x), and thus is uniquely determined by its values.) For other types, the uniqueness principle says that every map (function) from that type is uniquely determined by some data. (An example is the coproduct type introduced in Β§1.7 (http://planetmath.org/17coproducttypes), whose uniqueness principle is mentioned in Β§2.15 (http://planetmath.org/215universalproperties).)

    When the uniqueness principle is not taken as a rule of judgmental equality, it is often nevertheless provable as a propositional equality from the other rules for the type. In this case we call it a propositional uniqueness principle. (In later chapters we will also occasionally encounter propositional computation rules.)

The inference rules in Β§A.3 (http://planetmath.org/a3homotopytypetheory) are organized and named accordingly; see, for example, Β§A.2.4 (http://planetmath.org/a24dependentfunctiontypespitypes), where each possibility is realized.

The way to construct pairs is obvious: given a:A and b:B, we may form (a,b):AΓ—B. Similarly, there is a unique way to construct elements of 𝟏, namely we have ⋆:𝟏. We expect that β€œevery element of AΓ—B is a pair”, which is the uniqueness principle for products; we do not assert this as a rule of type theory, but we will prove it later on as a propositional equality.

Now, how can we use pairs, i.e. how can we define functions out of a product type? Let us first consider the definition of a non-dependent function f:A×B→C. Since we intend the only elements of A×B to be pairs, we expect to be able to define such a function by prescribing the result when f is applied to a pair (a,b). We can prescribe these results by providing a function g:A→B→C. Thus, we introduce a new rule (the elimination rule for products), which says that for any such g, we can define a function f:A×B→C by


We avoid writing g⁒(a,b) here, in order to emphasize that g is not a function on a product. (However, later on in the book we will often write g⁒(a,b) both for functions on a product and for curried functions of two variables.) This defining equation is the computation rule for product types.

Note that in set theory, we would justify the above definition of f by the fact that every element of AΓ—B is a pair, so that it suffices to define f on pairs. By contrast, type theory reverses the situation: we assume that a function on AΓ—B is well-defined as soon as we specify its values on tuples, and from this (or more precisely, from its more general version for dependent functions, below) we will be able to prove that every element of AΓ—B is a pair. From a category-theoretic perspective, we can say that we define the product AΓ—B to be left adjoint to the β€œexponential” Bβ†’C, which we have already introduced.

As an example, we can derive the projection functions

𝗉𝗋1 :AΓ—Bβ†’A
𝗉𝗋2 :AΓ—Bβ†’B

with the defining equations

𝗉𝗋1⁒((a,b)) :≑a
𝗉𝗋2⁒((a,b)) :≑b.

Rather than invoking this principle of function definition every time we want to define a function, an alternative approach is to invoke it once, in a universalPlanetmathPlanetmath case, and then simply apply the resulting function in all other cases. That is, we may define a function of type

𝗋𝖾𝖼AΓ—B:∏C:𝒰(Aβ†’Bβ†’C)β†’AΓ—Bβ†’C (1.5.2)

with the defining equation


Then instead of defining functions such as 𝗉𝗋1 and 𝗉𝗋2 directly by a defining equation, we could define

𝗉𝗋1 :≑𝗋𝖾𝖼AΓ—B(A,Ξ»a.Ξ»b.a)
𝗉𝗋2 :≑𝗋𝖾𝖼AΓ—B(B,Ξ»a.Ξ»b.b).

We refer to the function 𝗋𝖾𝖼AΓ—B as the recursor for product types. The name β€œrecursor” is a bit unfortunate here, since no recursion is taking place. It comes from the fact that product types are a degenerate example of a general framework for inductive types, and for types such as the natural numbersMathworldPlanetmath, the recursor will actually be recursive. We may also speak of the recursion principle for cartesian products, meaning the fact that we can define a function f:AΓ—Bβ†’C as above by giving its value on pairs.

We leave it as a simple exercise to show that the recursor can be derived from the projections and vice versa.

We also have a recursor for the unit type:


with the defining equation


Although we include it to maintain the pattern of type definitions, the recursor for 𝟏 is completely useless, because we could have defined such a function directly by simply ignoring the argument of type 𝟏.

To be able to define dependent functions over the product type, we have to generalize the recursor. Given C:AΓ—B→𝒰, we may define a function f:∏(x:AΓ—B)C⁒(x) by providing a function g:∏(x:A)∏(y:B)C⁒((x,y)) with defining equation


For example, in this way we can prove the propositional uniqueness principle, which says that every element of AΓ—B is equal to a pair. Specifically, we can construct a function


Here we are using the identity type, which we are going to introduce below in Β§1.12 (http://planetmath.org/112identitytypes). However, all we need to know now is that there is a reflexivityMathworldPlanetmath element 𝗋𝖾𝖿𝗅x:x=Ax for any x:A. Given this, we can define


This construction works, because in the case that x:≑(a,b) we can calculate


using the defining equations for the projections. Therefore,


is well-typed, since both sides of the equality are judgmentally equal.

More generally, the ability to define dependent functions in this way means that to prove a property for all elements of a product, it is enough to prove it for its canonical elements, the tuples. When we come to inductive types such as the natural numbers, the analogous property will be the ability to write proofs by induction. Thus, if we do as we did above and apply this principle once in the universal case, we call the resulting function inductionMathworldPlanetmath for product types: given A,B:𝒰 we have


with the defining equation


Similarly, we may speak of a dependent function defined on pairs being obtained from the induction principle of the cartesian product. It is easy to see that the recursor is just the special case of induction in the case that the family C is constant. Because induction describes how to use an element of the product type, induction is also called the (dependent) eliminator, and recursion the non-dependent eliminator.

Induction for the unit type turns out to be more useful than the recursor:


with the defining equation


Induction enables us to prove the propositional uniqueness principle for 𝟏, which asserts that its only inhabitant is ⋆. That is, we can construct


by using the defining equations


or equivalently by using induction:

Title 1.5 Product types