• No se han encontrado resultados

The extensions to the grammar to support inference are in Figure 6.2. These extensions all revolve around supporting unification variables, which are rather involved. One might think that unification variables need not be so different from ordinary variables; constraint generation could produce a telescope of these unification variables and solving simply produces a substitution. However, this naive view does not work out because of unification variable generalization.82

Consider a λ-abstraction over the variable x. When doing constraint generation inside of the λ, the kinds of fresh unification variables might mentionx. Here is a case in point, which will serve as a running example:

81Readers familiar with the internals of GHC may recognize itsAbsBinds data constructor in this

description. Formalizing all of its intricacies would indeed be required to infer the type of aletrec.

82The treatment of unification variables throughout

Bakeis essentially identical to the treatment

poly ::∀j (b::j)→...

example =λk a →poly k a

Type inference can easily discover that the kind of aisk. But in order for the inference algorithm to do this, it must be aware that k is in scope before a is. Note that when we call the solver (after type-checking the entire body of example), k is not in scope. Thus, as we produce the unification telescope during constraint generation over the body ofexample, we must somehow note that the unification variableα (the type of

a) can mentionk.

This means that unification variable bindings are quantified over a telescope ∆. (You can see this in the definition for u in Figure 6.2 on the preceding page.) In the

vocabulary of OutsideIn, the bindings in ∆ are the givens under which a unification variable should be solved for and a unification variable binding α:ρ∀∆.κ or ι : ∀∆.φ

with a non-empty ∆is an implication constraint.

6.3.1

Zonking

Solving produces a substitution from unification variables to types/coercions. Fol- lowing the nomenclature within GHC, I call applying this substitution zonking. The substitution itself, written Θ, is called a zonker.

Zonkers pose a naming problem. Consider solving to produce the zonker forexample, above. Suppose the type ofais assigned to beα. We would like to zonkαtok. However, as before,k is out of scope when solving for α. We thus cannot just write k/α, as that would violate the Barendregt convention, where we can never name a variable that is out of scope (as it might arbitrarily change due to α-renaming).

The solution to this problem is to have all occurrences of unification variables applied to vectors ψ.83 When we zonk a unification variable occurrence αψ, the vector ψ is substituted for the variables in the telescope ∆that α’s kind is quantified over.

Here is the formal definition of zonking:

Definition (Zonking [Definition E.19]). A zonker can be used as a postfix function. It operates homomorphically on all recursive forms and as the identity operation on leaves other than unification variables. Zonking unification variables is defined by these equations:

∀z.τ /α ∈Θ =⇒ αψ[Θ] = τ[ψ[Θ]/z] otherwise αψ[Θ] = αψ[Θ]

∀z.γ/ι∈Θ =⇒ ιψ[Θ] = γ[ψ[Θ]/z] otherwise ιψ[Θ] = ιψ[Θ]

Continuing the example from above, we would say that a has the type αk, where

we have α:Irrel∀k:IrrelType.Type. The solver will create a zonker with the mapping

83Recall thatψis a metavariable that can stand for either a type or a coercion. Thusψis a mixed

Σ; Ψty τ :κ Extra rule to support unification variables in types

α:Rel∀∆.κ∈Ψ Σctx Ψok

Σ; Ψvec ψ : ∆

Σ; Ψ ty αψ :κ[ψ/dom(∆)]

Ty_UVar

Σ; Ψcoγ :φ Extra rule to support unification variables in coercions

ι: ∀∆.φ∈Ψ Σctx Ψok

Σ; Ψvec ψ : ∆

Σ; Ψco ιψ :φ[ψ/dom(∆)]

Co_UVar Σctx Ψok Extra rules to support binding unification variables

Σ;Rel(Ψ,∆)ty κ:Type Σctx Ψok

Σctx Ψ, α:ρ∀∆.κok Ctx_UTyVar

Σ;Rel(Ψ,∆)prop φok ΣctxΨok

Σctx Ψ, ι: ∀∆.φ ok Ctx_UCoVar

Figure 6.3: Extra rules in Picojudgments to support unification variables

∀j.j/α (where I have changed the variable name for demonstration). This will zonk αk to becomej[k/j]which is, of course k as desired.

Note that the quantification we see here is very different from normalΠ-quantifica- tion in Pico. These quantifications are fully second class and may be viewed almost as suspended substitutions.

6.3.2

Additions to

Pico

judgments

The validity and typing judgments in Picoall work over signatures Σ and contexts Γ. In Bake, however, we need to be able to express these judgments in an environment where unification variables are in scope. I thus introduce mixed contexts Ψ, containing bothPico variables and unification variables.

Accordingly, I must redefine all of the Pico judgments to support unification variables in the context. These judgments are written with a turnstile in place of

Pico’s ` turnstile. There are also several new rules that must be added to support

unification variables. These rules appear in Figure 6.3.

Note the rules Ty_UVar and Co_UVar that support unification variable occurrences. The unification variables are applied to vectors ψ which must match the telescope ∆ in the classifier for the unification variable. In addition, this vector is substituted directly into the unification variable’s kind.

judgments, such as substitution and regularity. The statements and proofs are in Appendix E.

6.3.3

Untouchable unification variables

Vytiniotis et al. [99, Section 5.2] introduces the notion oftouchable unification variables, as distinct fromuntouchable variables. Their observation is that it is harmful to assign a value to a “global” unification variable when an equality constraint is in scope. “Global” here means that the unification variable has a larger scope than the equality constraint. We call the “local” unification variables touchable, and the “global” ones untouchable.

OutsideIn must manually keep track of touchability; the set of touchable unification

variables is an extra input to its solving judgment.

InBake, on the other hand, tracking touchability is very easy with its use of unifi- cation telescopes: all unification variables quantified by the same equality constraints as the constraint under consideration are touchable; the rest are untouchable.

To make this all concrete, let’s look at a concrete example (taken from Vytiniotis et al. [99]) where the notion of touchable variables is beneficial.

Suppose we have this definition:

dataT awhere

K :: (Bool ∼ a)⇒Maybe Int →T a

I have written this GADT with an explicit equality constraint in order to make the use of this constraint clearer. The definition for K is entirely equivalent to saying

K ::Maybe Int →T Bool.

We now wish to infer the type of

λx →casex of {K n→isNothing n}

where isNothing ::∀ a. Maybe a → Bool checks for an empty Maybe. Consider any mention of a new unification variable to be fresh. We assign x to have typeα0 and the

result of the function to have type β0. By the existence of the constructor K in the

case-match, we learn that α0 should really beT α1. Inside thecase alternative, we

now have a given constraintBool ∼α1. We then instantiate the polymorphicisNothing

with a unification variable β1, so that the type of isNothing is Maybe β1 →Bool. We

can now emit two equality constraints:

• The argument type toisNothing,Maybe β1, must match the type ofn,Maybe Int.

• The return type of the case expression (β0) is the return type of isNothing

Pulling this all together, we get the following unification telescope:

Ω = [ α0:IrrelType,

β0:IrrelType,

α1:IrrelType,

ι0:α0 ∼ Tα1,

β1:Irrel∀(c:Bool ∼ α1).Type,

ι1 : ∀(c:Bool ∼ α1).(Maybeβ1c ∼Maybe Int),

ι2 : ∀(c:Bool ∼ α1).(β0 ∼Bool)

Before we walk through what the solver does with such a telescope, what should

it do? That is, what’s the type of our original expression? It turns out that this is not an easy question to answer! The expression has no principal type. Both of the following are true:

(λx →casex of {K n →isNothing n}) ::∀a.T a→a

(λx →casex of {K n →isNothing n}) ::∀a.T a→Bool

Note that neither T a→a nor T a→Bool is more general than the other.

We would thus like the solver to fail when presented with this unification telescope. This is true, even though there is a solution to the inference problem (that is, a valid zonkerΘwith a telescope of quantified variables∆; see the specification of`solv, Section

6.1): ∆ =a:IrrelType Θ =T a/α0, Bool/β0, a/α1, hT ai/ι0, ∀c.Int/β1, ∀c.hMaybe Inti/ι1, ∀c.hBooli/ι2

The problem is that here is another valid substitution for β0 and ι2:

Θ = . . . ,

a/β0,

. . . ,

∀c.symc/ι2

These zonkers correspond to the overall type T a→Bool and T a→a, respectively. We must thus ensure that the solver rejects Ω outright. This is achieved by making β0 untouchable when considering solving the ι2 constraint.84 As described

by Vytiniotis et al. [99, Section 5.5], the solver considers the constraints individually. When simplifying (OutsideIn’s terminology for solving a simple, non-implication constraint) the ι1 and ι2 constraints, any unification variable not quantified by c is

considered untouchable.85 Thus, β

0 is untouchable when simplifyingι2, so the solver

will never set β0 to anything at all. It will remain an ambiguous variable and a type

error will be issued.

Contrast this with α1, which is also not set by the solver. This variable, however,

is fully unconstrained and can be quantified over and turned into the non-unification variablea. There is no way to quantify over β0, however.

Despite not setting β0, the solver is free to setβ1 which is considered touchable,

as it is also quantified by c. The unification variable β1 is fully local to the case

alternative body, and setting it can have no effect outside of the caseexpression. In the terminology of OutsideIn, that unification would be introduced by ∃β1 in an

implication constraint. In our example, the ability to set β1 means that we get only

one type error reported, not two.

Documento similar