• No results found

Thesis Statement

1.3 Canonical Structures

Canonical structures is a powerful overloading mechanism, heavily used in large formal-ization efforts like the Feit-Thompson Theorem (Gonthier et al.,2013a), in order to make notations and proofs tractable. We will see in Chapter2 that canonical structures can be cleverly used also for proof automation. This section is an introduction to canonical structures, starting with a canonical—in the sense of common—example and concluding with an overview of its semantics. In Chapter 4 we will provide a detailed description of its semantics.

We have to note that, in the literature and everyday use of Coq, the word “structure” is used interchangeably (and confusingly) to mean both dependent records and the types

E;Σ ` Γ

E;Σ; Γ ` Prop : Type(1) Ax1

E;Σ ` Γ i < j

E;Σ; Γ ` Type(i) : Type(j) Ax2

` E ∀Γ0. {. . . ; i : T := . . . ; . . .} ∈ E E;Σ; Γ ` i : ∀Γ0. T Ax3

` E ∀Γ0. {. . . ; i : T := {. . . ; k : U ; . . .}; . . .} ∈ E

E;Σ; Γ ` k : ∀Γ0. U Ax4

E;Σ ` Γ (x : T ) ∈ Γ or (x := t : T ) ∈ Γ

E;Σ; Γ ` x : T Var

E;Σ ` Γ (c : T ) ∈ E or (c := t : T ) ∈ E

E;Σ; Γ ` c : T Const

E;Σ; Γ ` T : s s ∈ S E;Σ; Γ, x : T ` U : Prop

E;Σ; Γ ` ∀x : T. U : Prop Prod1 E;Σ; Γ ` T : Type(i) i ≤ k E;Σ; Γ, x : T ` U : Type(j) j ≤ k

E;Σ; Γ ` ∀x : T. U : Type(k) Prod2

E;Σ; Γ, x : T ` t : U E;Σ; Γ ` ∀x : T. U : s E;Σ; Γ ` λx : T. t : ∀x : T. U Lam E;Σ; Γ ` u : U E;Σ; Γ ` t : ∀x : U. T

E;Σ; Γ ` t u : T {u/x} App E;Σ; Γ ` u : U E;Σ; Γ, x := u : U ` t : T

E;Σ; Γ ` let x := u : U in t : T {u/x} Let E;Σ ` Γ

(?x : T [Ψ]) ∈ Σ ∨ (?x := t : T [Ψ]) ∈ Σ E;Σ; Γ ` σ : Ψ

E;Σ; Γ ` ?x[σ] : T {σ/ bΨ} Metavar E;Σ; Γ ` t : i t0 ∀Γ0. {. . . ; i : T := {k : ∀Γ0. U }; . . .} ∈ E

∀j E;Σ; Γ, Γ0, Γ0j ` uj : ρ t0 (kj0j)

E;Σ; Γ ` matchρt with k x ⇒ u end : ρ t0 t Case

∀l E;Σ; Γ ` Tl: sl E;Σ; Γ, f : T ` tl: Al tl satisfy the guarded condition

E;Σ; Γ ` fixj {f /n : T := t} : Tj Fix E;Σ; Γ ` t : T T ≡ U

E;Σ; Γ ` t : U Check-Conv

Figure 1.5: Typing judgment for CIC with meta-variables.

E;Σ; Γ ` · : · Id

E;Σ; Γ ` σ : Ψ E;Σ; Γ ` t : T {σ/ bΨ}

E;Σ; Γ ` (σ, t) : (Ψ, x : T ) Assumption E;Σ; Γ ` σ : Ψ E;Σ; Γ ` t : T {σ/ bΨ} t =βζδ u{σ/ bΨ}

E;Σ; Γ ` (σ, t) : (Ψ, x := u : T ) Definition

Figure 1.6: Typing judgment for substitutions.

they inhabit. To disambiguate, in this thesis we use structure for the type, instance for the value, and canonical instance for a canonical value of a certain type. We will use the term canonical structures only when referring generally to the use of all of these mechanisms in tandem.

The following definition is a simplified example of a structure (i.e., type) taken from the standard Ssreflect library (Gonthier and Mahboubi,2010):

Structure eqType := EqType { sort : Type;

equal : sort → sort → bool;

: ∀x y : sort. equal x y ↔ x = y }

The definition makes eqType a record type, with EqType as its constructor, taking three arguments: a type sort, a boolean binary operation equal on sort, and a proof that equal decides the equality on sort. For example, one possible eqType instance for the type bool, may be

eqType bool := EqType bool eq bool pf bool

where eq bool x y := (x && y) || (!x && !y), and pf bool is a proof, omitted here, that ∀x y : bool. eq bool x y ↔ x = y. (Note that, in Coq, although it may seem as though EqType is declared as taking a single record argument with three components, applications of EqType pass the three arguments in curried style.)

The labels for the record fields serve as projections out of the record, so the definition of eqType also introduces the constants:

sort : eqType → Type

equal : ∀A:eqType. sort A → sort A → bool

We do not care to project out the proof component of the record, so we declare it anonymous by naming it with an underscore.

Notational Convention 3. We will usually omit the argument A of equal, and write equal t u instead of equal T t u, as T can be inferred from the types of t and u. We

use the same convention for other functions as well, and make implicit such arguments that can be inferred from the types of other arguments. This is a standard notational convention in Coq.

It is also very useful to define generic instances. For example, consider the eqType instance for the pair type A × B, where A and B are themselves instances of eqType:

eqType pair (A B : eqType) :=

EqType (sort A × sort B) (eq pair A B) (pf pair A B) where

eq pair (A B : eqType) (u v : sort A × sort B) :=

equal (π1 u) (π1 v)&&equal (π2 u) (π2 v)

and pf pair is a proof, omitted just like pf bool above, that ∀A B : eqType. ∀x y : (sort A × sort B). eq pair x y ↔ x = y.

Declaring both eqType bool and eqType pair now as canonical instances—using Coq’s Canonical keyword—will have the following effect: whenever the type checker is asked to type a term like equal (b1, b2) (c1, c2), where b1, b2, c1 and c2 are of type bool, it will generate a unification problem matching the expected and inferred type of the first non-implicit argument of equal, that is,

sort ?e ≈ bool × bool

for some meta-variable ?e, generated implicitly at the application of equal.

Notational Convention 4. In some sections or chapter we will not bother with contex-tual types for meta-variables, as they play no role in the examples therein. In these cases we will overload the notation ?x to refer to both the meta-variable and the application of the meta-variable to an implicit suspended substitution.

In the equation above, Coq will try to solve this problem using the canonical instance eqType pair, resulting in two new unification subproblems, for fresh meta-variables ?A and ?B:

sort ?A ≈ bool sort ?B ≈ bool

Next, it will choose ?A := eqType bool and ?B := eqType bool, with the final result that equal (b1, b2) (c1, c2) reduces implicitly to eq bool b1 c1 && eq bool b2 c2, as one would expect.

In this manner, canonical instances can be used for overloading, similar to the way type classes are used in Haskell (Hall et al.,1996,Wadler and Blott,1989).3 We can declare a number of canonical eqType instances, for various primitive types, as well as generic in-stances for type constructors (like the pair example above). Then we can uniformly write equal t u, and the typechecker will compute the canonical implementation of equality at the types of t and u by solving for equal’s implicit argument A.

1.3.1 Formalities

In Coq, a structure is not a primitive element of the language; it is encoded as a particular inductive type: it has only one constructor, and it generates one projector for each argument of the constructor. The general syntax is

Structure i Γ0: s := k {p1 : U1; . . . ; pn: Un}

where Γ0 is a list of arguments of the type. Each pj is a projector name. This language construct generates an inductive type

{ i : ∀Γ0. s := { k : ∀Γ0. ∀p : U . i cΓ0 } } and for each projector name pj it generates a projector function:

λΓ0. λz : i cΓ0. match s with k x1 . . . xj . . . xn⇒ xj end : ∀Γ0. ∀z : i cΓ0. Uj An instance ι of the structure is created with the constructor k:

ι := ∀Γ1. k t1 . . . tm+n

where m is the number of arguments of the structure. Terms t1 to tm correspond to the arguments of the structure, and tm+1 to tm+n to each of the pj.

As we saw in the previous section, the important aspect of structures is that their instances can be deemed “canonical”. A canonical instance instructs the unification algorithm to instantiate a structure meta-variable with the instance, if certain conditions hold. More precisely, a canonical instance populates the canonical instance database

dbwith triples (pj, hj, ι), where hj is the head constant appearing in value tm+j. (As a matter of fact, hj can also be an implication (→), a sort, or a variable.) Then, whenever

3It is worth noting that Coq also provides a built-in type class mechanism, but this feature is inde-pendent of canonical structures. We discuss Coq type classes more in Section5.

the unification algorithm has to solve a problem of the form

pj ?s ≈ hj u (1.2)

it instantiates ?s with ι.

For instance, in the unification equation generated by the equal application above, the projector pj is sort, the head constant hj is (· × ·), and the head constant arguments u are bool and bool.

If the head symbol of the field pjin instance ι is a variable, then ι is chosen for unification with ?s, irrespectively of h in equation (1.2). In this case, we refer to ι as a default canonical instance for pj.

We emphasize that: (1) to control the number of (pj, hj)-pairs that the typechecker has to remember, we will frequently anonymize the projections if they are not important for the application, as in the case of the proof component in eqType above; (2) there can only be one specified canonical instance for any given pj and hj. In particular, overlapping canonical instances for the same pj and hj are not permitted. This limitation, however, can be easily circumvented, as we will see shortly in §2.1.