• No results found

3.1 Type Constructors and Kinds

3.1.1 Syntax

The syntax of type constructors and kinds is given in Figure 3.1. The language of type constructors (represented by the metavariable C) is a completely standard variant of Fω.1 It contains a set of base types b—in particular, unit, product, arrow, universal and existential types—as well as unit, pairing and function operators (and corresponding elimination forms) for building type constructors of higher kind. Constructor variables, written α, are drawn from some countably infinite set

ConVars. Although a let construct is not included as primitive, it is easily encodable. I will sometimes write “let α= C1 inC2” as shorthand for π2hα= C1,C2i.2

A word about variable bindings: Throughout this thesis, I employ the standard technique of syntactically identifying any two expressions that differ only in their choice of bound variable names. Unless otherwise specified, all the binding constructs I use look like “hx=e1, e2i”, “letx=

e1 in e2”, or “x:e1.e2”, where x is some variable (be it constructor, term or module variable), and

the e’s are syntactic expressions of some form (be they kinds, constructors, etc.). In all of these 1

The expressive power of ML only requires us to use the predicative form ofFω[61], but I have chosen for simplicity

to make this language impredicative.

2

The Stone-Harper calculus only provides a pair construct of the form hC1,C2i. The one I employ here, which

bindsαto C1 inside C2, is not strictly necessary, but I have found it to be rather convenient. In Dreyeret al.[11]

I verified that Stone and Harper’s meta-theory is essentially unchanged when one allows this variant of the pair construct. In a similar vein, Stone and Harper do not include a unit kind either, but supporting it requires only a trivial and obvious extension to their meta-theory (again verified in Dreyeret al.[11]).

Constructor Variables α, β ∈ ConVars

Kinds K,L ::= 1|T|

s

(C) |Σα:K1.K2 |Πα:K1.K2

Transparent Kinds K,L ::= 1|

s

(C)|Σα:K1.K2 |Πα:K1.K2

Type Constructors C,D ::= α|b| hi | hα= C1,C2i |πiC|λα:K.C|C1(C2)

Base Types b ::= unit|C1×C2 |C1→C2 | ∀α:K.C| ∃α:K.C

Static Contexts ∆ ::= ∅ |∆, α:K

Figure 3.1: Syntax of Type Constructors and Kinds

cases, x is assumed to be bound in e2. Thus, for example: In the pair constructor hα= C1,C2i,

the variable α stands for the constructor C1 inside C2. In the function constructor λα:K.C, the

argument variable α, whose kind is K, is bound in the body C. In addition, I will use the notation e[e1,· · ·, en/x1,· · ·, xn] to denote the simultaneous capture-avoiding substitution of e1,· · ·, en for

x1,· · ·, xn, respectively, ine.

Now for the interesting part: the kind language. Let us look at the different kind forms one at a time. The unit kind 1 classifies only one type constructor, namely the unit constructor hi, not to be confused with the base type unit. The base kind T, which in many presentations of Fω is written as∗or Ω, classifies those types which themselves classify terms. In a closed program, every type constructor of base kind will be reducible to a syntactic base type b.

The other base kind is the singleton kind

s

(C), a subkind of T that classifies precisely those

type constructors that are equivalent to C. As explained in Section 2.2.3, singletons allow one to support a notion of “type definition” within a regular kind structure. Furthermore, the combination of the “opaque” base kindTand the “transparent” singleton kind

s

(C) provide a natural basis for

translucent signatures in the module language.

The dependent pair kind Σα:K1.K2 classifies pairs of constructors whose first component has

kind K1 and whose second component has kind K2, where α stands for the first component. In

other words, a constructor C has kind Σα:K1.K2 if and only ifπ1C has kind K1 and π2C has kind

K2[π1C/α]. When the bound variableα does not appear free in K2, I will sometimes write the pair

kind as K1×K2.

The dependent arrow kind Πα:K1.K2 classifies constructor functions that take an argument of

kind K1 and return a result of kind K2, where α stands for the argument. Thus, a constructor C

has kind Πα:K1.K2 if and only if, whenever D has kind K1, C(D) has kind K2[D/α]. When the

bound variable α does not appear free in K2, I will sometimes write the arrow kind as K1→K2.

While the primitive singleton kind

s

(C) is only valid when C has kind T, singletons at higher

kind are in fact definable in terms of the primitive kinds. Figure 3.2 defines a meta-level function

s

K(C), which returns a subkind of K classifying precisely those constructors that are equivalent

to C (assuming C actually has kind K).3 At the base kindsT and

s

(D),

s

K(C) is defined as just

the primitive singleton

s

(C). The definition of

s

K(C) at the remaining kinds reflects the fact that

constructor equivalence in the Stone-Harper calculus is extensional, i.e., if two constructors are impossible to distinguish by their uses then they are as good as equivalent. Specifically, if we read D’s membership in

s

K(C) as “D is equivalent to C at kind K,” then we see from the definition

of

s

K(C) that (1) D is equivalent to C at pair kind when π1D is equivalent to π1C and π2D is

equivalent to π2C, (2) D is equivalent to C at arrow kind when D(α) is equivalent to C(α), and (3)

3

3.1. TYPE CONSTRUCTORS AND KINDS 43

s

1(C) def= 1

s

T(C) def=

s

(C)

ss

(D)(C) def =

s

(C)

s

Σα:K1.K2(C) def=

s

K1(π1C)×

s

K 2[π1C/α](π2C)

s

Πα:K1.K2(C) def= Πα:K1.

s

K2(C(α))

Figure 3.2: Singletons at Higher Kinds

Can(1) def= hi

Can(

s

(C)) def= C

Can(Σα:K1.K2) def= hα=Can(K1),Can(K2)i

Can(Πα:K1.K2)

def

= λα:K1.Can(K2)

Figure 3.3: Canonical Constructors of Transparent Kinds

all constructors of unit kind are equivalent because they are all equally useless.

The definition of higher-order singletons given in Figure 3.2 is not the only possible one. For in- stance,

ss

(D)(C) and

s

Σα:K1.K2(C) could just as well be defined as

s

(D) and Σα:

s

K1(π1C).

s

K2(π2C), respectively. It is also likely possible to make

s

K(C) a primitive kind instead of a macro, and to

build in the definitional equations in Figure 3.2 as kind equivalence rules. This would have the slight disadvantage, however, of losing the property that kind equivalence and subtyping (discussed below) are syntax-directed. For simplicity, I have avoided any complications by defining

s

K(C)

precisely as Stone and Harper do.

Higher-order singletons are a special case of a more general subclass of kinds that I call “trans- parent” and denote by the metavariable K. The syntax of transparent kinds, given in Figure 3.1,

requires essentially that no instances of the opaque base kindTappear on the right-hand side of an arrow. A transparent kindKhas the property that any two constructors of kindKare equivalent,

and in fact transparent kinds are the only kinds to enjoy this property. Consequently, given any transparent kind K, Figure 3.3 shows how to construct a “canonical” constructor Can(K) of kind K, which is guaranteed to be equivalent to any other inhabitant ofK. Transparent kinds will be

needed primarily in order to define a notion of transparent signatures in Chapter 4.

Finally, I define a notion ofstatic contexts, written ∆, which bind constructor variables to their kinds. I call these contexts static so as to distinguish them from dynamic contexts Γ that also bind value and module variables. For all forms of contexts, I require that all variables bound in a context be distinct in order for the context to be syntactically valid. I will also sometimes treat a context as a (meta-level) function from variables to classifiers,e.g., ifα:K∈∆, then ∆(α) = K.