• Aucun résultat trouvé

Rewrite Rules for Overloading Resolution

Implicit Overloading

4.2.3 Rewrite Rules for Overloading Resolution

Now we present the compiler machinery to actually keep track of theoverload andinstance declarations and to do instance resolution. We describe this in terms of a rewrite rule operational semantics. This, combined with the high level overloading processing algorithm described above, forms the complete overloading resolution mechanism of the compiler. Readers unfamiliar with the notation of Term Rewriting Systems should refer to [33, 34] for an excellent treatment.

Our term rewriting system consists of the type predicate terms as specied syntactically in gure 4.2 and rewrite rules over them. More formally, our rewrite system is a pair (

;R

) where,

, also called the signature, is the set of function symbols in the system. It is exactly the union of the set of overloading predicate functions in the predicate clauses (+?,double?,

:::

) and the set of type constructors in our type system (I,B,->,list,2 tuple,

:::

). It also records the arity of each symbol.

also implicitly contains innitely many variables which is precisely the set of all type variables in our case.

R

, the set of rewrite rules, consist of a left hand side (LHS) which is always a single predicate clause, and a right hand side (RHS) which is a collection of zero or more predicate clauses.

The predicate functions and their rewrite rules are accumulated by the compiler as it pro-cesses the explicitly and implicitly overloaded identiers. Since this process is necessarily incre-mental, we will always view the rewrite system current at the time of a particular compilation to be the complete set of rewrite rules accumulated till that time. Any forward references can

is only a matter of choosing among constants.

OVERLOAD: overload

x

=

`

x

: (

x

?

1

n)

:

(

i 2FV(

)) INSTANCE:

instance

x

o=

x

i

TE `

x

o :

o

:

o

TE `

x

i :

i

:

i

S

= U(

o

;

i) Rule:

S

o x0i

,,!

S

i

IMPL-FUNCTION:

def

f x

1

x

n= block

b is the set of all overloading predicate clauses in block

b,!!

u (

u in normal form)

Rule: (

f

?

1

n),,!

u (

i 2FV(

u))

Figure 4.4: Meta-Inference rules to generate Rewrite Rules for Overloading Resolution.

be detected and agged by the independent incremental compilation mechanism described in chapter 3.

The gure 4.4 shows the meta-inference rules used by the compiler to generate the rewrite rules of this system. We discuss them below. The meta-variable

varies over the set of type predicates. A type substitution when applied to a predicate performs the substitution over each type expression in each clause of the predicate.

An overload declaration species a HMT template that all its instances will share. We want to express restrictions on the template in order to help the type inference process as much as possible, because this template is the only visible type signature for that overloaded identier. Note that a trivial template of the form (*0) has much less information than the template (*0 -> *0 -> *0), which denotes a curried function of two arguments of the same type giving the result of the same type. The compiler also generates a new predicate function (the overloaded identier suxed with a \?") to be added to the current rewrite system. It assigns the arity of the predicate function to be the number of distinct type variables appearing in the HMT template. The distinct type variables represent the various independent ways in which that identier can be overloaded. We capture these degrees of freedom by supplying an equal number of parameters to the predicate function, one for each type variable in the HMT

overload (+) = *0 -> *0 -> *0;

overload (*) = *0 -> *1 -> *2;

generate the predicate clauses (+? *0)and (*? *0 *1 *2). The latter form for \*" gives the exibility of expressing multiplication of unlike types, e.g., vectors with matrices to give vectors.

An instance declaration produces a rewrite rule for the overloaded identier. The type context of the resolution is obtained by unifying a copy of the HMT template of the overloaded identier with that of the instance identier. The generated rule rewrites the instantiated predicate of the overloaded identier into that of the instance identier12. As an example, the following declarations,

Implicit overloading of function identiers is handled by the last rule in gure 4.4. During the initial type checking phase, the type of an overloaded identier (its HMT template) gets suitably instantiated to reect the type context in which it is being used. In the second pass, its type predicate is unied with this type context and resolved. This involves repeated rewriting of the instantiated type predicate using the existing set of rewrite rules until it can not be rewritten any more (it reaches a normal form). We will show in the next section that this rewriting always terminates (under certain restrictions) and produces the same answer irrespective of the order in which the rewrite rules are applied. In literature, these properties are called Strong Normalization and Conuence respectively. These are strong properties of the rewrite system and ensure correct compiler behaviour even in the face of random accumulation of rewrite rules as in our incremental compiler.

The normal form either consists of the trivial null predicate \

", in which case the identier in question has been completely resolved, or there are unresolved predicates left over. Predicates

12We also record an appropriate translation identier over the rewrite rule to help us in translation. We will describe this in more detail in the next section.

may not get fully resolved either because the appropriate instances that cover the type context at hand are not available (as in attempting to resolve \2+x" without the instancedeclaration ofiplus), or it could simply be that sucient information is not present in the type context (as in attempting to resolve \x+x" in the declaration ofdouble). We have chosen to interpret the former situation as an error in the resolution algorithm of gure 4.3 for essentially pragmatic reasons.

Finally, all unresolved predicates are collected up to the nearest enclosing function denition and we generate a rewrite rule to denote this implicit overloading as shown in gure 4.4. The predicate function goes by the name of the function identier and its arity is the number of distinct type variables present in the unresolved predicates, just as in the case of explicit overloading declarations.

4.2.4 Properties of the Rewrite System