• No se han encontrado resultados

1. DEFINICIÓN DEL PROBLEMA

4.3 MARCO LEGAL

5.3.2 Presentación de las sesiones

The typing rules in Picoare all parameterized by both a signature Σ and a context

Γ. Signatures contain bindings for all global constants: type and data constructors. In contrast, contexts contain local bindings, for type and coercion variables. Several treatments of System FC assume a fixed, global signature, but I find it more precise here to make dependency on this signature explicit.

5.4.1

Signature validity

The judgment to check the validity of a signature follows:

`sig Σok Signature formation

`sig ∅ok Sig_Nil

Σ`ctx a:Irrelκok T # Σ

`sig Σ,T:(a:κ)ok Sig_ADT

T:(a:κ)∈Σ Σ`ctx a:Irrelκ,∆ok K # Σ

`sig Σ,K:(∆;T)ok Sig_DataCon

We see here the two different entities that can belong to a signature, an algebraic datatype (ADT)T or a data constructor K.

An ADT is classified only by its list of universally quantified variables (often shortened to universals), as this is the only piece of information that varies between ADTs. For example, the Haskell type Int contains no universals, while Either contains two (both of kind Type), andProxy’s universals are (a :Type,b :a). The relevance of universals is predetermined (see Section 5.4.2.2) and so no relevance annotations appear on ADT specifications. Additionally, coercion variables are not permitted here—coercion variables would be very much akin to Haskell’s misfeature of datatype contexts49 and so are excluded.

A data constructor is classified by a telescope ∆ of existentially bound variables (or existentials) and the ADT to which it belongs. The grammar for telescopes is the same as that for contexts, but we use the metavariables Γ and ∆ in distinct ways: Γ

is used as the context for typing judgments, whereas ∆is more often used as some component of a type. A telescope is a list of binders—both type variables and coercion variables—where later binders may depend on earlier ones. A data constructor’s existentials are the data that cannot be determined from an applied data constructor’s type. In this formulation, the term existential also includes what would normally be considered term-level arguments.

For example, let’s consider these Haskell definitions:

dataTuple awhere

MkTuple ::∀a.Int →Char →a →Tuple a dataEx awhere

MkEx ::∀a b.b→a →Ex a

If I have a value of type Tuple Double, then I know the types of the data stored in a

MkTuple, but I do not know theInt, theChar, or theDouble—these are the existentials. Similarly, if I have a value of typeEx Char, then I know the type of one argument to

MkEx, but I do not know the type of the other; I also know neither value. In this case, the second type, b, is existential, as are both values (of types b and a, respectively).

The use of the term existential to refer to term-level arguments may be non- standard, but it is quite convenient (while remaining technically accurate) in the context of a pure type system with ADTs.

5.4.2

Looking up type constants

Information about type constants is retrieved via the Σ`tc H : ∆1; ∆2;H0 judgment,

presented in Figure 5.5 on the following page. This judgment retrieves three pieces of data about a type constantH: its universals, its existentials, and the head of the result type. It is best understood in concert with the typing rule that handles type constants, which also uses the typing judgment on vectors—ordered lists of arguments—also presented in Figure 5.5 on the next page. Let’s tackle this all in order of complexity. 49See discussion of how this is a misfeature at https://prime.haskell.org/wiki/ NoDatatypeContexts.

Σ`tc H : ∆1; ∆2;H0 Σ`ctx Γok

Σ;Rel(Γ)`vec τ :Rel(∆1)

Σ; Γ`ty H{τ} :’Π(∆2[τ /dom(∆1)]).H0τ Ty_Con

Σ`tc H : ∆1; ∆2;H0

Type constant kinds, with universals ∆1,

existentials∆2, and result H0

Σ`tc Type:∅;∅;Type Tc_Type

T:(a:κ)∈Σ

Σ`tc T :∅;a:Relκ;Type Tc_ADT

K:(∆;T)∈Σ T:(a:κ)∈Σ

Σ`tc K :a:Irrelκ; ∆;T Tc_DataCon

Σ; Γ`vec ψ : ∆ Type vector formation

Σ`ctxΓok Σ; Γ`vec ∅:∅ Vec_Nil Σ; Γ`ty τ :κ Σ; Γ`vecψ : ∆[τ /a] Σ; Γ`vec τ, ψ :a:Relκ,∆ Vec_TyRel Σ;Rel(Γ)`ty τ :κ Σ; Γ`vec ψ : ∆[τ /a] Σ; Γ`vec {τ}, ψ :a:Irrelκ,∆ Vec_TyIrrel Σ;Rel(Γ)`co γ :φ Σ; Γ`vec ψ : ∆[γ/c] Σ; Γ`vec γ, ψ :c:φ,∆ Vec_Co

5.4.2.1 The constant Type

The constant Type has no universals, no existentials, and Type’s type is Type, as

Tc_Type tells us. Thus, in the use of Ty_Con whenH{τ} is just Type{} (normally, we omit such empty braces), we see that ∆1, ∆2, and τ are all empty, meaning that

we get Σ; Γ`ty Type:Type, as desired.

5.4.2.2 Algebraic datatypes

Let’s considerMaybe as an example. We see that the list of universals ∆1 is empty for

all ADTs. Thus, the list of universal argumentsτ must be empty inTy_Con. The list of existentials ∆2 is a:RelType and the result type root is Type, both by Tc_ADT.

We thus get Σ; Γ`ty Maybe :’Πa:RelType.Type, as desired. (Note that a is unused in

the body of the ’Π and thus that this type could also be written as Type→Type.) I have argued here how the rules work out this case correctly, but it may surprise the reader to see that the argument to Maybe is treated as an existential here—part of ∆2—and not a universal. This could best be understood if we consider Type itself

to be an open ADT (that is, an extensible ADT) with no universal parameters. To make this even more concrete, here is how it might look in Haskell:

dataTypewhere Bool ::Type

Int ::Type

Maybe ::Type→Type

Proxy ::∀(k::Type).k →Type ...

Thinking of ADTs this way, we can see why the argument to Maybe is existential, just like other arguments to constructors (see Section 5.4.1 for an explanation of the unusual use of the word existential here). We can also see that the kind parameter k

toProxy is also considered an existential in this context.

The last detail to cover here is the relevance annotation on the a, as assigned in Tc_ADT: all the variables are considered relevant. This is a free choice in the design of Pico. Any choice of relevance annotations would work, including allowing the user to decide on a case-by-case basis. I have chosen to mark them as relevant, however, with the consideration that these ADTs might be present at runtime. There is nothing inPico that restricts ADTs to be present only at compile time; the user might write a runtime computation that returns Bool, for example.50 (Such a facility replaces Haskell’s current TypeRep facility [75].) By marking the ADT parameters as relevant, a runtime decision can be made between, say, Maybe Int and Maybe Bool. This seems useful, and so I have decided to make these parameters relevant.

50This statement does not mean that you can extract the valueMaybe Int from Just 3, which

5.4.2.3 Data constructors

The most involved case is that for data constructors, where both the universals and the existentials can be non-empty. We’ll try to understand Ty_Con first by an example inspired by the Haskell expression Left True::Either Bool Char. Let’s recall the definition of Either, a basic sum type:

dataEither::Type→Type→Typewhere Left ::a →Either a b

Right::b →Either a b

In Picothis looks like the following:

Σ =Either:(a :Type,b:Type),Left:(x:Rela;Either),Right:(x:Relb;Either),

Bool:(),True:(;Bool),False:(;Bool),Char:() Σ;`ty Left{Bool,Char}True :Either Bool Char

We see how the universal argumentsBool andChar to the constructorLeft are specified in the subscript; without these arguments, there would be no way to get the type of

Left True in a syntax-directed way.

Universal argument saturation The grammar for type constant occurrences in types requires them to appear fully saturated with respect to universals but perhaps unsaturated with respect to existentials. There are several reasons for this seemingly peculiar design:

• It is helpful to separate universals from existentials in a variety of contexts. For example, existentials are brought into scope on acase-match, while universals are not. Separating out these arguments is also essential in the step rule S_KPush.

• If Pico did not allow matching on unsaturated constants, it might be most natural to require saturation with respect to both universals and existentials (while still keeping these different arguments separate). This would allow, for example, for a simple statement of the canonical forms lemma (Lemma C.75), because only a λ-expression would have a Π-type.

However, sincePicodoes allow matching on unsaturated constants, the grammar must permit this form. Because Pico tracks the difference between matchable ’Π and unmatchable

˜

Π, we retain the simplicity of the canonical forms lemma, as any expression classified by a ’Π must be a partially applied constant and any expression classified by a

˜

Π must be a λ.

• All universal arguments are always irrelevant and erased during type erasure (Section 5.11). It is thus natural to separate these from existentials in the

As with many design decisions, it is possible to redesign Pico and avoid this unusual choice, but in my opinion, this design pays its weight nicely.

Typing rules for data constructors The Tc_DataCon rule looks up a data

constructor K in the signature Σ to find its telescope of existentials ∆ and parent datatype T. The second premise of the rule then looks up T to get the universals. The universals are annotated with Irrel, as universals are always irrelevant in data constructors—universal arguments are properly part of the type of a data constructor and are thus not needed at runtime. The telescope of existentials ∆ and datatypeT are also returned from `tc.

RuleTy_Conchecks the supplied arguments τ against the telescope of universals, here named ∆1. Note that τ are checked against Rel(∆1); the braces that appear in

the productionH{τ} are part of the concrete syntax and do not represent wrapping each individual τ ∈ τ in braces (cf. Section 5.6.2). Rule Ty_Con then builds the result type, a ’Π-type binding the existentials and producing H0—that is, the parent typeT—applied to all of the universals.

Documento similar