• No results found

4.1 External Syntax

4.3.5 Types

Figure 4.12 Initial constraint generator (ExtLabSynt → Env)

Types (ty ) (G10)Jtvl, αK = tv = αl (G11)Jdty ltc e l, α0 K = ∃hα, δi.Jty , αK;Jltc , δK;(α 0 l= α δ) (G12)Jty1 l → ty2, αK = ∃hα1, α2i.Jty1, α1K;Jty2, α2K;(α l = α1 α2)

Rule (G10) handles the case where an external type variable is being dealt with which occurs in a constructor binding. As a result, an accessor is generated (this should be connected during solving to the binder occurring in the declaration of the datatype which declares the constructor in which this explicit type variable

4.3. CONSTRAINT GENERATION

is used). Rule (G11) is for labelled datatype constructors occurring in definitions of datatype constructors, and rule (G12) handles the case where an arrow type is specified in the user program.

4.3.6

Datatype names

Figure 4.13 Initial constraint generator (ExtLabSynt → Env)

Datatype names (dn)

(G13)Jdtv tc el, α0K = ∃hα, γ i.(α0 l= α γ);(tc= γ);(l tv = α)l

Datatype names are handled with rule (G13). By looking at this rule it can be seen that datatype declarations have exactly one explicit type variable argument. Binders are created for both the name of the datatype and for the specified type variable argument in this rule.

4.3.7

Constructor bindings

Figure 4.14 Initial constraint generator (ExtLabSynt → Env)

Constructor bindings (cb) (G14)Jdconlc, αK = dcon = αl

(G16)Jdcon oflty, αK = ∃hα0, α1i.Jty , α1K;(α

0 l= α

1 α);(dcon

l

= α0)

Rules (G14) and (G16) give support for datatype constructor bindings to the con- straint generator. (G14) is for a constructor which doesn’t take an argument and rule (G16) is for constructors defined with the of keyword, where the type of the argument for the datatype constructor is defined. In both cases, binders are created for the name of the constructor.

4.3. CONSTRAINT GENERATION

4.3.8

Declarations

Figure 4.15 Initial constraint generator (ExtLabSynt → Env)

Declarations (dec)

(G17)Jval rec pat = expl K =

∃hα1, α2, ev i.(ev = poly(Jpat , α1K;Jexp , α2K;(α1

l = α2)));evl (G18)Jdatatype dn l = cbK = ∃hα1, α2, ev i.(ev = ((α1 l = α2);Jdn , α1K;poly(Jcb , α2K)));ev l

(G19)Jopenl stridK = ∃ev .(strid = ev );evl l

Functions are supported in the constraint generator with rule (G17). Function declarations are not supported using the fun keyword in this presentation of the core but the implementation does handle this, which is simply a syntactic variation. In this rule, as in rule (G18), the novel poly environments are used to make function bindings and datatype declarations polymorphic. The open feature is handled with rule (G19), where an accessor constraint using the structure identifier is created.

4.3.9

Structure declarations

Figure 4.16 Initial constraint generator (ExtLabSynt → Env)

Structure declarations (strdec)

(G20)Jstructure strid = strexpl K = ∃hev , ev0i.[Jstrexp , ev K];(ev0= (strid = ev ));evl 0l

Rule (G20) handles structure declarations. The environment generated for that structure is wrapped with [e] to limit the scope of bindings occurring in that struc- ture.

4.3.10

Structure expressions

Figure 4.17 Initial constraint generator (ExtLabSynt → Env)

Structure expressions (strexp) (G21)Jstrid

l, ev

K = strid

l

= ev

(G22)Jstructl strdec1· · · strdecn end, evK =

∃ev0.(ev= evl 0);(ev0= (Jstrdec1K; · · · ;JstrdecnK))

Structure expressions are handled in rules (G21), which handles the case where the structure expression is some identifier which an accessor is created for, and (G22) in

4.4. CONSTRAINT SOLVING

the case of a struct expression, in which case environments are generated for each structure declaration and compose the results using the environment composition operator (;).

4.4

Constraint solving

This section discusses the constraint solver, which takes constraints which were generated during the previous section and terminates in either one of two states:

• A success state succ.

• A failure state err(er ). In this case an error is returned of the one of the kinds discussed in section 4.18.

Readers familiar with the earlier presentation of the Skalpel core in chapter 3 will notice that there is no longer a constraint solving context returned by the constraint solver (∆) when it terminates in success. The reason for this simplification is that the set of unifiers is no longer bundled along with an environment (written hu, ei) as firstly the set of unifiers is now considered a global entity of the constraint solver (discussed further in section 4.4.1), and secondly because of the new stack mechanism to replace what used to be multiple constraint solving calls in the same rule. The stack mechanism is discussed in section4.6.3.

Let the set of monomorphic type variables be defined as follows: m ∈ Monomorphic ::= hα, d i

Figure 4.18 Additional syntactic forms used by constraint solver

er ∈ Error ::= hek , d i

ek ∈ ErrKind ::= clash(µ1, µ2) | circularity

state ∈ State ::= slv(−→e , d , m,−→st , e0) | succ | err(er )

Additional syntactic forms that are used by the constraint solver (defined in figure

4.19) are shown in figure4.18. The symbol−→st is defined in section4.6.3.

The constraint solving process starts in the form slv(h>i, ∅, ∅, hi, e), and ends either in the form succ, which indicates success, or in the state err(er ) where er is either a type constructor clash or a circularity error (figure4.18).

The relations isErr and solvable are defined below, where → indicates a constraint solving step and →∗ is the reflexive and transitive closure of →. The Solved is also redefined as shown below.

4.4. CONSTRAINT SOLVING

solvT ∈ Solved ::= Env ∪ StrDec

isErr : Env → Error

e isErr→ er ⇔ slv(>, d , ∅, ∅, e) →err(er )

solvable : State → {true, f alse}

solvable(e) ⇔ slv(>, d , ∅, ∅, e) →∗ succ

solvable : Solved → {true, f alse}

solvable(strdec) ⇔ ∃e.strdec → e ∧ solvable(e)

4.4.1

Unifiers

In this constraint solving presentation (figure4.19), unifiers are stored in U .

When constraint solving is started, U = ∅. During the constraint solving process, nothing is ever subtracted from U , this set is only added to. The set of unifiers is available for use by the constraint solver, and any associated functions called by it. While U is a function, it can be considered as a special kind of directed acyclic graph {V,E}, where V are vertices and E are edges, and where for each vertex Vx,

the edge Vx 7→ Vx0 occurs at most once. When using an application U (Vx), vertex

Vx0 will be returned where a path from Vx to Vx0 exists (if it does not, Vx = Vx0) and

Vx0 7→ V00

x does not exist. For example, where U = {{V1, V2, V3, V4, V5, V6}, {V1 7→

V3, V3 7→ V2, V4 7→ V5, V2 7→ V6}}, U (V1) = V6. In the case where the term applied

to is an arrow type V1 → V2, this is computed as U (V1) → U (V2) (and similarly for

an application).

The unifier set is defined in this way now so that it not hidden inside another constraint solving form, which led to awkward expressions in the old presentation where the ∆ had to be broken down into both its components in order to use each of them, and when there were new and old versions of ∆ (e.g. ∆ and ∆0), there then exists u and u0, u would never be used and always use u0. For these reasons it was decided to break up the coupling of unifier sets with environment information.

4.4. CONSTRAINT SOLVING

Figure 4.19 Constraint solver (1 of 2) : State → State

equality constraint reversing

(R) slv(−→e , d , m,−→st , ct = ct0) → slv(−→e , d , m,−→st , ct0= ct ), if s = Var ∪ Dependent ∧ ct0 ∈ s ∧ ct 6∈ s equality simplification (S1) slv(−→e , d , m,−→st , ct = ct ) → isSucc(−→e , m,−→st ) (S2) slv(−→e , d , m,−→st , ctd0= ct0) → slv(−→e , d ∪ d0, m,−→st , ct = ct0) (S3) slv(−→e , d , m,−→st , τ1 µ1= τ2 µ2) → slv(−→e , d , m,−→st , (µ1= µ2);(τ1= τ2)) (S4) slv(−→e , d , m,−→st , τ1 τ2= τ3 τ4) → slv(−→e , d , m,−→st , (τ1= τ3);(τ2= τ4)) (S5) slv(−→e , d , m,−→st , τ1= τ2) → slv(−→e , d , m, − → st , µ = arr), if {τ1, τ2} = {τ µ, τ3 τ4} (S6) slv(−→e , d , m,−→st , µ1= µ2) → err(hclash(µ1, µ2), d i), if{µ1, µ2} ∈ {{γ, γ0}, {γ, arr}}∧γ 6= γ0 unifier access

Rules (U1) through (U4) have also the common side condition v 6= ct ∧ y = U (xd) ∧v /∈ dom(U )

(U1) slv(−→e , d , m,−→st , v = ct ) → err(hcircularity, deps(y)i), if v ∈ vars(y)\Env ∧ strip(y) 6= v (U2) slv(−→e , d , m,−→st , v = ct ) → isSucc(−→e , m,−→st ), if v /∈ Env∧ strip(y) = v (U3) slv(−→e , d , m,−→st , v = ct ) → isSucc(−→e , m,−→st ), if v /∈ vars(y) ∪ Env ∧ U = U ⊕ {v 7→ y} (U4) slv(−→e , d , m,−→st , v = ct ) → slv(−→e @h>i, d , m,−→st @−→st0, ct ), if v ∈ Env ∧−→st0 = hhnew, d , m, v ii (U6) slv(−→e , d , m,−→st , v = ct ) → slv(−→e , d , m,−→st , z = ct ), if U (v) = z binders/empty/dependent/variables

(B) slv(−→e , d , m,−→st ,vid =α) → isSucc(−→e ;vid = α, m ∪ {αd¯ d},−→st ) (B2) slv(−→e , d , m,−→st , bind) → isSucc(−→e ; bindd, m,−→st ),

if bind 6=vid =α (X) slv(−→e , d , m,−→st , ∃a.e0) → slv(−→e , d ∪ d0, m,−→st , e0[{a 7→ a0}]), if a0 ∈ atoms(hU , e/ 0i) (E) slv(−→e , d , m,−→st , >) → isSucc(−→e , m,−→st ) (D) slv(−→e , d , m,−→st , e0d 0 ) → slv(−→e , d ∪ d0, m,−→st , e0) (V) slv(−→e , d , m,−→st , ev ) → isSucc(−→e ; evd¯, m,−→st ) composition environments (C1) slv(−→e , d , m,−→st , e1;e2) → slv(−→e , d , m, − →