Coherence for Qualiied Types

ions and let expressions. Any such renaming is permitted so long as we avoid clashes with free variables. The nal group of structural rules in Figure 5 is closely modeled on the typing rules for OP and can be used to describe the reduction of subterms within a given term. 3.3 Equalities between terms The rules in Figure 6 de ne the equality relation for terms in OP as the transitive, symmetric closure of the reduction relation described above. The rst two rules ensure that P jA ` E = F : P jA ` F = E : P jA ` E = E 0 : P jA ` E 0 = E 00 : P jA ` E = E 00 : P jA ` E > F : P jA ` E = F : Figure 6: De nition of equality between terms. equality is an equivalence relation. There is no need to include re exivity here since this is a direct consequence of the structural rules in Figure 5. The last rule shows how reductions give rise to equalities. In practice, many of the rules used in the de nition of equality above will be used implicitly in the proof of equalities between terms. The following example uses all three of the rules in Figure 6 (as well as subject reduction to justify the fact that the intermediate steps are well-typed): P jA ` let x = E in [F=x ]F 0 = [E=x ]([F=x ]F 0) ( -let) = [[E=x ]F=x ]F 0 = let x = [E=x ]F in F 0 : ( -let) The context in which this equality is established (given by P , A and ) does not play a part in the calculation. Examples like this are quite common and we will often avoid mentioning the context altogether in such situations, writing ` E = F to indicate that P j A ` E = F : for any choice of P , A and for which the required side conditions hold. The above property of let expressions may seem unfamiliar, and it is worth illustrating why it is useful in our work. Suppose that ; `̀ e : Eq Int and that (==) denotes an equality function of type 8a:Eq a ) a ! a ! Bool . Now consider the OML term: let f = ( x : y:x == y) in f 2 3: Since the function f is only ever applied to integer values, it is su cient to treat f as having type Int ! Int ! Bool , with translation: let f = ( x : y:(==) e x y) in f 2 3 However, the type inference algorithm calculates the type of f as 8a:Eq a ) a ! a ! Bool and results in a translation of the form: let f = ( v : x : y:(==) v x y) in f e 2 3: The following calculation shows that these translations are equal and hence that it is possible to eliminate the evidence abstraction used in the second case. The second step is justi ed by the result above. ` let f = ( v : x : y:(==) v x y) in f e 2 3 = let f = ( v : x : y:(==) v x y) in [f e=f ](f 2 3) = let f = [ v : x : y:(==) v x y=f ](f e) in f 2 3 = let f = ( v : x : y:(==) v x y) e in f 2 3 = let f = ( x : y:(==) e x y) in f 2 3 As in the last step here, many equalities between terms can be obtained by replacing one subterm with an equivalent term. These steps are justi ed by the structural rules in Figure 5 and are often used implicitly in proofs. 4 Conversions One of the most important tools in the treatment of type inference is the ordering relation used to describe when one (constrained) type scheme is more general than another. For example, assuming that ; `̀ e :Eq Int , the ordering: (8a:Eq a ) a ! a ! Bool) (Int ! Int ! Bool) might be used to justify replacing an integer equality function, say primEqInt :: Int!Int!Bool with a generic equality function with the more general type 8a:Eq a)a!a! Bool as in the previous section. This breaks down in OP due to the presence of evidence abstraction and application: simply replacing primEqInt with (==) in primEqInt 2 3 does not even give a well-typed expression! The correct approach is to replace primEqInt by (==) e. More generally, we will deal with examples like this using OP terms as an interpretation of the ordering between type schemes. For each 0 we identify a particular collection of terms that we call conversions from to 0. Each such conversion is a closed OP term C : ! 0 and hence any term of type can be treated as having type 0 by applying the conversion C to it. One possible conversion for the example above is: ( x :xe) : (8a:Eq a )a!a!Bool)!(Int!Int!Bool): Note that the type of this conversion (as in the general case) cannot be expressed as an OML type scheme since it uses the richer structure of OP types. For the purposes of type inference it would be su cient to take any term C of type ! 0 as a conversion for 0 but this is clearly inadequate if we are also concerned with the semantics of the terms involved; we can only replace E with CE if we can guarantee that these terms are equivalent, except perhaps in their use of evidence abstraction and application. More formally, we need to ensure that ` Erase (CE) = Erase E for all OP terms E (or at least, all those occurring as translations of OML terms). Since Erase (CE) = (Erase C ) (Erase E), the obvious way to 6 ensure that this condition holds is to require that Erase C is equivalent to the identity term id = x :x . These ideas extend to conversions between arbitrary constrained type schemes. It is tempting to de ne the set of conversions from (P 0 j 0) to (P j ) as the set of all closed OP terms C : (P j ) ! (P 0 j 0) for which Erase C is equivalent to id . In practice it is more convenient to choose a more conservative de nition that gives more information about the structure of conversions: De nition 3 Suppose = (8 i :Q ) ), 0 = (8 j :Q 0 ) 0) and none of j appear free in , P or P 0. A conversion C from (P j ) to (P 0 j 0), written C : (P j ) (P 0 j 0), is a closed OP term of type (P j )! (P 0 j 0) such that: Erase C = id, v :P 0;w :Q 0 `̀ e :P ; f : [ i= i ]Q, 0 = [ i= i ] , and ` C = x : v : w :xef for some types i , evidence variables v and evidence e. It is straightforward to verify that the term x : v : w :xef mentioned in this de nition is a conversion from (P j ) to (P 0 j 0) and it follows that any equivalent OP term with the same type will also be a conversion of the same kind. On the other hand, we cannot assume that all such conversions will be equivalent to this particular term since there may be more than one choice for the types i and hence for the evidence expressions f in the de nition above. It is immediate from the de nitions above that (P j ) (P 0 j 0) if and only if there is a conversion C : (P j ) (P 0 j 0) (this may require renaming the bound variables of 0 to apply the de nition of conversions). As a result, all of the properties of the ( ) ordering described in [7] can be extended to analogous results for conversions. For example, the following proposition shows that re exivity of ( ) corresponds to the identity conversion while transitivity of ( ) corresponds to composition of conversions. Proposition 1 For any (P j ) there is a conversion id : (P j ) (P j ). Furthermore, if C : (P j ) (P 0 j 0) and C 0 : (P 0 j 0) (P 00 j 00), then (C 0 C ) : (P j ) (P 00 j 00) where (C 0 C ) x :C 0(Cx ). From a categorical perspective, this proposition can be used to show that there is a category whose objects are type schemes and whose arrows are (equivalence classes of) conversions. The only additional properties needed to justify this are that the composition of equivalence classes is wellde ned and associative, both of which are easily veri ed. The ordering relation ( ) is preserved by substitutions and the corresponding result for conversions is: Proposition 2 If C : (P j ) (P 0 j 0) and S is a substitution of types for type variables, then C :S(P j ) S(P 0 j 0). The ordering between type schemes extends to an ordering between (constrained) type assignments, writing (P jA) (P 0 jA0) to indicate that (P jA(x )) (P 0 jA0(x )) for each x 2 dom A = dom A0. It is useful to extend the de nition of conversions to orderings between type assignments. For the purposes of this work, it is su cient to consider only the case of orderings of the form A A0 and A (P jA0), the rst of which is just a special case of the second with P = ;. One simple approach would be to de ne a conversion for an ordering A (P jA0) as a function that gives a conversion from A(x ) to (P j A0(x )) for each x 2 dom A. However, whereas we might use a conversion C : (P j 0) to treat a term of type as having type 0, we will typically use a conversion between type assignments to simultaneously replace each occurrence of a variables mentioned in the type assignment with an appropriate new term. From this perspective it seems more sensible to think of a conversion between type assignments as a term substitution. Furthermore, the translations of a term are calculated with respect to a particular predicate assignment (the rst component in a derivation v : P j A ` E ; E 0 : ) and may involve the evidence variables in the domain of that assignment. It is therefore necessary to specify these variables explicitly as part of the type of the conversion. De nition 4 A conversion C from a type assignment A to a constrained type assignment (v : P j A0) with the same domain, written C :A (v : P jA0), is a substitution such that: dom C dom A = dom A0. In particular, if x 62 dom A, then Cx x . ( x : v :Cx ) :A(x ) (P jA0(x )) for each x 2 dom A. Note that the expression Cx in this de nition denotes an application of a (meta-language) substitution to a particular variable; C is not an OP term. Continuing with the previous example and assuming that ; `̀ e :Eq Int , one possible conversion for the type assignment ordering f(==) : Int ! Int ! Boolg f(==) : 8a:Eq a ) a ! a ! Boolg would be the substitution that maps (==) to (==) e and xes every other variable. To see how this might be used, consider an OP term in which the (==) has been treated as having type Int ! Int ! Bool . If we replace this with a generic equality function with the more general type, then we need to include the evidence e for Eq Int with every use of (==). This is precisely the e ect obtained by applying the conversion to the original term. 5 Syntax-directed translation The next two sections follow the development of [7] to describe the relationship between an arbitra