4.1 External Syntax
4.2.2 Quantification and Schemes (σ)
In this presentation of the Skalpel core, there is no longer the concept of dummy variables and instead all variables are quantified. This has the advantage of re- moving the machinery surrounding freshness that was present in the original pre- sentation of the core. There is no longer any use for the Dum set as all variables are now quantified, and so it has been removed in this chapter. This means that dummy internal type variables, dummy environment variables, and dummy type constructor variables no longer exist.
There are three kinds of universally quantified schemes in this system - internal
4.2. CONSTRAINT SYNTAX
Figure 4.2 Syntax of constraint terms
CL ∈ IntLabSynt (the union of all sets below and Label) .
ev ∈ EnvVar (environment variables)
δ ∈ TyConVar (type constructor variables)
γ ∈ TyConName (type constructor names)
α ∈ ITyVar (internal type variables)
d ∈ Dependency ::= l µ ∈ ITyCon ::= δ | γ | arr | hµ, d i τ ∈ ITy ::= α | τ µ | τ1 τ2| hτ , d i ts ∈ ITyScheme ::= ∀v . τ tcs ∈ ITyConScheme ::= ∀v . µ es ∈ EnvScheme ::= ∀v . e c ∈ EqCs ::= µ1= µ2 | e1= e2 | τ1= τ2
bind ∈ Bind ::= tc =tcs | strid =es | tv =ts | vid =ts
acc ∈ Accessor ::= tc =δ |strid =ev | tv =α | vid =α
e ∈ Env ::= > | ev | bind | acc | c | poly(e) | ∃a.e | e2;e1 | he, d i
ct ∈ CsTerm ::= τ | µ | e
σ ∈ Scheme ::= ts | tcs | es
v ∈ Var ::= α | δ | ev
a ∈ Atom ::= v | γ | d
dep ∈ Dependent ::= hct , d i
type schemes, type constructor schemes and environment schemes. All schemes are subject to alpha-conversion (e.g. the schemes ∀α1. α1 and ∀α2. α2 are equivalent).
By not having dummy variables any longer, the issue of erroneously creating acci- dental bindings to dummy variables and checking for dummy variables in conditions of e.g. monomorphic variable computation (further discussion of this given in sec- tion 4.6).
4.2.3
The constraint/environment form (e)
The form e should be considered as both a constraint and an environment. Such a form can be any of the below:
• The empty environment / satisfied constraint. This is represented by the symbol >.
• An environment variable. To abbreviate, [e] is written instead of (∃ev .ev = e), where ev does not occur in e. This is a constraint which enforces the log- ical constraint nature of e while limiting the scope of its bindings. Note that the bindings can still have an effect if e constrains an environment variable. This used to be a dummy variable assignment in the old presentation of the core.
4.2. CONSTRAINT SYNTAX
• A composition environment. The operator ‘;’ is used to compose envi- ronments, which is associative. Note that e;>, >;e, and e are considered to be equivalent.
• A binder/accessor. A binder is of the form id =σ, and an accessor is of the form id =v . Binders represent program occurrences of an identifier id that are being bound, and accessors represent a place where that binding is used. For example, in the environment
vid =x;vid =α
the internal type variable α is constrained through the binding of vid to be an instance of x. It is often also the case that binders and accessors can be connected without being next to each other. In an environment such as
vid =x;...;vid =α
it is possible that the binder and accessor of vid are connected. There are some environment forms that can be in the omitted (...) section which will mean that the accessor and the binder will be disconnected. Section 4.2.6on shadowing specifies which forms would cause this.
To abbreviate, vid =ct is written instead of vid =∀∅. ct , and vid = ct toy abbreviate hvid =ct , yi (similarly for accessors).
• An equality constraint. A constraint which creates the condition of two pieces of constraint syntax that they should be in some way equal.
• Existential environment. The form ∃v.e, binds all free occurrences of v that occur free in e. The notation ∃hv1, v2, v3. · · · , vni.e is used to abbreviate
∃v1.∃v2.∃v3. · · · ∃vn.e.
• A polymorphic environment poly(e). This environment promotes binders in the argument to poly to be polymorphic.
• Dependent form. An environment annotated with dependencies acts like an environment only when the dependencies are satisfied.
4.2.4
Syntactic forms
Defined here is atoms(CL), which is a syntactic form set belonging to Var ∪ Label ∪ Dependency and occurring in CL.
4.2. CONSTRAINT SYNTAX
Functions are defined to extract variables, labels, and dependencies from a con- straint term in figure4.3.
Figure 4.3 Definition of sets of variables, labels and dependencies
vars : CL → P(Var)
vars(CL) = atoms(CL) ∩ Var (set of variables)
labs : CL → P(Label)
labs(CL) = atoms(CL) ∩ Label (set of labels)
deps : CL → P(Dependency)
deps(CL) = atoms(CL) ∩ Dependency (set of dependencies)
4.2.5
Semantics of constraints/environments
The set of renamings and substitutions are defined in figure 4.4. Note that Ren ⊂ Sub. Renamings are used to instantiate type schemes, and substitution is defined in figure4.5, where given a constraint term and a substitution, a resulting constraint term is produced.
Figure 4.4 Renaming and substitutions
Ren : ITyVar → ITyVar
ren ∈ Ren = {ren ∈ ITyVar → ITyVar | ren is injective
∧ dj(dom(ren), ran(ren))}
Sub : SubstTerm → SubstTerm
sub ∈ Sub = {f1∪ f2 | f1 ∈ Unifier ∧ f2∈ TyConName → TyConName}
The unifier set is defined as a directed acyclic graph as follows, where V = ITyVar ∪ ITy ∪ ITyCon and E = P(V × V) which specify directional edges:
Unifier : ITyVar → ITyVar U ∈ Unifier = {V, E}
Note that for each Vx ∈ V, the edge Vx 7→ Vx0 occurs at most once, and so U is
also considered as a function. 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→ Vx00
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. During application, if U (v ) = CLx and
4.2. CONSTRAINT SYNTAX
Figure 4.5 Substitution semantics
a[sub] =
x, if sub(a) = x
a, otherwise
(τ µ)[sub] = τ [sub] µ[sub]
(τ1 τ2)[sub] = τ1[sub] τ2[sub]
ctd[sub] = ct [sub]d
(ct1= ct2)[sub] = (ct1[sub] = ct2[sub])
(e1;e2)[sub] = e1[sub];e2[sub]
(∀v . ct )[sub] = ∀v . ct [sub] s.t. dj(v , atoms(sub))
(∃a.e)[sub] = ∃a.e[sub] s.t. dj({a}, atoms(sub))
(id =v )[sub ] =
(id =v [sub ]), if v [sub] ∈ Var
undefined, otherwise
(id =σ)[sub ] = (id =σ[sub ])
poly(e)[sub] = poly(e[sub])
x[sub] = x, otherwise
4.2.6
Shadowing
In an environment it may be the case that some parts are shadowed and so inacces- sible. Consider the environment bind1; ev; bind2. In the event that ev /∈ dom(U ), it
can also be said that ev shadows bind1 because ev could potentially be bound to
an environment which rebinds bind1. The predicate shadowsAll is defined in figure
4.6. We write shadowsAll(e) for shadowsAll(h∅, ei).
Figure 4.6 Shadowing function : Unifier × Env → {true, f alse}
shadowsAll(hU , ei) ⇐⇒
(e = ev ∧ (shadowsAll(hU , U (ev )i) ∨
ev 6∈ dom(U )))
∨ (e = (e1;e2) ∧ (shadowsAll(hU , e1i) ∨
shadowsAll(hU , e2i)))
∨ (e = he0, d i ∧ shadowsAll(hU , e0i))
∨ (e = ∃a.e0 ∧ shadowsAll(hU , e0i)∧
a 6∈ dom(U ))
Figure4.7 shown the semantics of accessing an identifier in an environment , in the context where there is access to a unifier set U during constraint solving.
Figure 4.7 Accessing the Semantics
(id =σ)(id ) = σ (ed)(id ) = ∀v . ctd, if (e)(id ) = ∀v . ct (e1;e2)(id ) =
(e2)(id ), if (e2)(id ) is defined
undefined, if (e2)(id ) is undefined ∧ shadowsAll(hU , e2i)
(e1)(id ), otherwise (ev )(id ) = (e)(id ), if U (ev ) = e undefined, otherwise (hei)(id ) = e(id )
(he1i@he2i)(id ) = (e1; e2)(id )
Note that the application of an existential environment to an identifier is undefined as such an environment represents incomplete information.
4.3. CONSTRAINT GENERATION
4.2.7
Relations
Two instance relations are defined here, the use of which can be seen in constraint solving. These have been updated from the definition in the original presentation of the core to deal with the new use of type schemes and existential quantification of terms.
∀v . ct , sub −−−−−−instance→ ct [sub] if dom(sub) = v
σ −−→ cte if ∃sub.σ, sub −−−−−−instance→ e, ct
4.3
Constraint generation
The initial constraint generator is defined in figure 4.17. This is referred to as the initial constraint generator because constraints are also generated during the constraint solving process (section 4.4).
Let cstgen0(PL, v ) be a function with two arguments, the first a labelled piece of
user program PL, and the second a set of free variables occurring in PL. Each of the constraint generation rules is written either as JPLK = e (which abbrevi- ates cstgen0(PL, {})) or as JPL, vK = e (which abbreviates cstgen0(PL, {v })). Let cstgen(PL) = cstgen0(PL, {}).
It can be seen that datatype declarations only have one constructor by looking at rules (G17), (G14) and (G16). The core has been defined in the manner in order to reduce the complexity of the core. In rule (G13), datatype names are defined to have exactly one type variable argument.
Structure declarations are handled in rule (G20). In the core, signatures to constrain these structures are not presented, but this extension to the core can be found in section6.4.
In order that environments can be sliced out correctly, environment variables are annotated with labels, such as in rule (G4). Such environment variables must be annotated with a label otherwise it could not be sliced out, and that environment variable would then shadow any following environment, even if the program point the label was assigned to was itself sliced out.
Readers should see chapter 8 for lemmas and proofs concerning this constraint generator. Each of the constraint generation rules are now discussed in turn.
4.3. CONSTRAINT GENERATION
4.3.1
Expressions
Figure 4.8 Initial constraint generator (ExtLabSynt → Env)
Expressions (exp) (G1) Jvidle, αK = vid = αl
(G2)Jletldec in exp end, αK = [∃α2.Jdec K;Jexp , α2K;(α
l = α2)] (G3)Jdexp atexp e l, α K = ∃hα1, α2i.Jexp , α1K;Jatexp , α2K;(α1 l = α2 α) (G4)Jfn pat ⇒ exp, αl K = [∃hα1, α2, ev i.(ev =Jpat , α1K);ev
l;
Jexp , α2K;(α
l
= α1 α2)]
Rule (G1) generates accessors for value identifiers. For example, where a function previously defined is applied to an argument, the accessor which connects the use of this function to its definition is generated in this rule.
Rule (G2) handles let expressions, where some declarations are to be defined in the scope of some expression. We accomplish this with the [e] notation in this rule - by encasing the environments from the declaration inside square brackets, upon closing of these brackets that environment is not exported (as described previously) and so binders inside are not available to following expressions.
Applications are handled with rule (G3). Here the → piece of constraint syntax is used to represent the expression part being used as a function.
Nameless functions are handled in rule (G4). The environment variable is labelled in this rule (and similarly in other rules) in order that declarations which have been sliced out do not shadow their context. If the environment variable was not labelled, then it would shadow the context it was in irrespective if some environment was sliced out or not.
4.3.2
Labelled datatype constructors
Figure 4.9 Initial constraint generator (ExtLabSynt → Env)
Labelled datatype constructors (ldcon) (G5)Jdconl, αK = dcon = αl
Labelled datatype constructors are handled in rule (G5). With this rule, an accessor is created to a datatype constructor in the same way as in (G1). The way datatype constructors and value identifiers are differentiated is enhanced in section 14.1 of [Rah10].
4.3. CONSTRAINT GENERATION
4.3.3
Patterns
Figure 4.10 Initial constraint generator (ExtLabSynt → Env)
Patterns (pat ) (G6)Jvvarlp, αK = vvar = αl (G7)Jdcon l p, αK = dcon l = α (G8)Jdldcon atpat el, α K = ∃hα1, α2i.Jldcon , α1K;Jatpat , α2K;(α1 l = α2 α)
Rule (G6) creates bindings for value variables occurring in patterns (such as in function declarations), while rule (G7) creates accessors to datatype constructors occurring in patterns. Rule (G8) handles the use of datatype constructors in pat- terns which have an argument.
4.3.4
Labelled type constructors
Figure 4.11 Initial constraint generator (ExtLabSynt → Env)
Labelled type constructors (ltc) (G9)Jtc
l, δ
K = tc
l
= δ
Labelled type constructors can occur in rule (G9). An accessor is created for this type constructor. This constraint can be generated for example in datatype con- structor bindings.