We investigate a technique from the literature, called the phantom types technique, that uses parametric polymorphism, type constraints, and unification of polymorphic types to model a subtyping hierarchy. Hindley-Milner type systems, such as the one found in ML, can be used to enforce the subtyping relation. We show that this technique can be used to encode any finite subtyping hierarchy (including hierarchies arising from multiple interface inheritance). We then formally demonstrate the suitability of the phantom types technique for capturing subtyping by exhibiting a type-preserving translation from a simple calculus with bounded polymorphism to a calculus embodying the type system of ML.
IntroductionIt is well known that traditional type systems, such as the one found in Standard ML [10], with parametric polymorphism and type constructors can be used to capture program properties beyond those naturally associated with a Hindley-Milner type system [9]. For concreteness, let us review a simple example, due to Leijen and Meijer [8]. Consider a type of atoms, either booleans or integers, that can be easily represented as an algebraic datatype: datatype atom = I of int I B of bool There are a number of operations that we may perform on such atoms (see Figure 1 (a)). When the domain of an operation is restricted to only one kind of atom, as with conj and double, a run-time check must be made and an error or exception reported if the check fails.One aim of static type checking is to reduce the number of run-time checks by catching type errors at compile time. Of course, in the example above, the ML type system does not consider conj (mki 3, mkB true) to be ill-typed; evaluating this expression will simply raise a run-time exception.If we were working in a language with subtyping, we would like to consider integer atoms and boolean atoms as distinct subtypes of the general type of atoms and use these subtypes to refine the types of the operations. Then the type system would report a type error in the expression double (mkB false) at compile time. Fortunately, we can write the operations in a way that utilizes the ML type system to do just this. We