Download
phantom types and subtyping n.
Skip this Video
Loading SlideShow in 5 Seconds..
Phantom Types and Subtyping PowerPoint Presentation
Download Presentation
Phantom Types and Subtyping

Phantom Types and Subtyping

112 Vues Download Presentation
Télécharger la présentation

Phantom Types and Subtyping

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. Phantom Types and Subtyping Matthew Fluet Riccardo Pucella Dept. of Computer Science Cornell University

  2. The Setting (I) • Modern strongly typed functional language • Parametric polymorphism • val id:  = fn x => x • Type constraints • val idInt: intint = fn x => x • Datatypes and type constructors • datatype  tree = Leaf of  | Node of  tree  tree TCS2002

  3. The Setting (II) • Modern strongly typed functional language • Limited expressibility at foreign function interfaces • No polymorphic types • No user defined datatypes • No primitive notion of subtyping TCS2002

  4. The Problem datatype atom = I of Int | B of bool fun mkI (i:int):atom = I(i) fun mkB (b:bool):atom = B(b) fun toString (v:atom):string = ... fun double (v:atom):atom = ... fun conj (v1:atom, v2:atom):atom = ... toString (mkI 1)  “1” toString (mkB false)  “false” double (mkB true) run-time error conj (mkI 3, mkB true) run-time error TCS2002

  5. Wish List • Raise compile-time type errors on domain violations rather than run-time errors • toString should apply to all atoms • double should only apply to integer atoms • conj should only apply to boolean atoms • Preserve the implementation • Would like to treat integer and boolean atoms as subtypes of all atoms TCS2002

  6. A First Solution (I) type All, Int, Bool datatype atom = I of int | B of bool fun mkI (i:int):Intatom = ... fun mkB (b:bool):Boolatom = ... fun toString (v:Allatom):string = ... fun double (v:Intatom):Int atom = ... fun conj (v1:Boolatom, v2:Boolatom):Boolatom = ... double (mkB true) compile-time type error; Int atom  Bool atom conj (mkI 3, mkB true) compile-time type error; Bool atom  Int atom toString (mkI 1) compile-time type error; Int atom  All atom toString (mkB false) compile-time type error; Bool atom  All atom TCS2002

  7. Phantom Types type All, Int, Bool datatype atom = I of int | B of bool fun mkI (i:int):Intatom = ... fun mkB (b:bool):Boolatom = ... • Phantom types • Abstract types that need not have any corresponding run-time values • Phantom type variables • Type instantiations of  in  atom do not contribute to the run-time representation of atoms TCS2002

  8. A First Solution (II) type All, Int, Bool datatype atom = I of int | B of bool fun mkI (i:int):Intatom = ... fun mkB (b:bool):Boolatom = ... fun toString (v:Allatom):string = ... fun double (v:Intatom):Int atom = ... fun conj (v1:Boolatom, v2:Boolatom):Boolatom = ... fun intToAll (v:Int atom):All atom = v fun boolToAll (v:Bool atom):All atom = v toString (intToAll (mkI 1))  “1” toString (boolToAll (mkB false))  “false” TCS2002

  9. A Better Solution type All, Int, Bool datatype  atom = I of int | B of bool fun mkI (i:int):Intatom = ... fun mkB (b:bool):Boolatom = ... fun toString (v:atom):string = ... fun double (v:Intatom):Int atom = ... fun conj (v1:Boolatom, v2:Boolatom):Boolatom = ... double (mkB true) compile-time type error; Int atom  Bool atom conj (mkI 3, mkB true) compile-time type error; Bool atom  Int atom toString (mkI 1) well typed; Int atom unifies with  atom toString (mkB false) well typed; Bool atom unifies with  atom TCS2002

  10. The Phantom Types Technique • Use a superfluous type variable and type constraints to encode “extra” information • Underlies many interesting uses of type systems • Foreign function interfaces • Embedded languages • Uncaught exception analysis • A “folklore” technique TCS2002

  11. Contributions • A general encoding of subtyping hierarchies into phantom types • A formalization of one use of the phantom types technique TCS2002

  12. Outline • A recipe for interfaces and implementations • Encoding subtyping hierarchies • Bounded polymorphism • Formalization TCS2002

  13. Features of the example An underlying primitive type of values A set of operations A hierarchy of implicit subtypes mkI 1 Int int atom toString All  string  atom  string All Int Bool From Subtyping to Polymorphism TCS2002

  14. The Recipe • Given: • A primitive type p • An implicit subtyping hierarchy 1,…,n • An implementation of p and its operations • Derive • A “safe” interface (the types) • A “safe” implementation (the code) • Restrictions • Shared representation and operations TCS2002

  15. Applying the Recipe • Given: • A primitive type: atom • An implicit subtyping hierarchy: All, Int, Bool • An implementation: structure Atom • Derive • A “safe” interface: signature SAFE_ATOM • A “safe” implementation: structure SafeAtom TCS2002

  16. Deriving the Interface (I) • 1C unifies with 2A iff 12 • Introduce type  • Encode each implicit type  as   • 1 unifies with 2 iff 12 • Example: • AllC = unit AllA =  • IntC = int IntA = int • BoolC = bool BoolA = bool TCS2002

  17. Deriving the Interface (II) • Use concrete encodings in all covariant type positions • Use abstract encodings in most contravariant type positions TCS2002

  18. Deriving the Interface (III) signature ATOM = sig type atom val mkI: int -> atom val mkB: bool -> atom val toString: atom -> string val double: atom -> atom val conj: atom * atom -> atom end  signature SAFE_ATOM = sig type  atom val mkI: int -> IntCatom val mkB: bool -> BoolCatom val toString: AllAatom -> string val double: IntAatom -> IntCatom val conj: BoolAatom * BoolAatom -> BoolCatom end TCS2002

  19. Applying the Recipe • Given: • An abstract type: atomp • An implicit subtyping hierarchy: All, Int, Boolp • An implementation: structure Atomp • Derive • A “safe” interface: signature SAFE_ATOM • A “safe” implementation: structure SafeAtom  TCS2002

  20. Deriving the Implementation (I) • Need a type  isomorphic to p • the type system should consider 1 and 2 equivalent iff 1 and 2 are equivalent • Opaque signature constraint • Hides all type implementation details TCS2002

  21. Deriving the Implementation (II) structure SafeAtom1:> SAFE_ATOM = struct type  atom = Atom.atom val mkI = Atom.mkI val mkB = Atom.mkB val toString = Atom.toString val double = Atom.double val conj = Atom.conj end TCS2002

  22. Applying the Recipe • Given: • An abstract type: atomp • An implicit subtyping hierarchy: All, Int, Boolp • An implementation: structure Atomp • Derive • A “safe” interface: signature SAFE_ATOM • A “safe” implementation: structure SafeAtom   TCS2002

  23. Encoding Subtyping Hierarchies (I) • Powerset lattice encoding • S = {s1,…,sn} is a finite set • Ordered by inclusion X  S XC= t1  …  tn where ti = unit if si  X unit z otherwise XA= t1  …  tn where ti = i if si  X i z otherwise TCS2002

  24. All = {s1, s2} Int = {s1} Bool = {s2} None = {} Encoding Subtyping Hierarchies (II) AllC = unit  unit IntC = unit  unit z BoolC = unit z  unit NoneC = unit z  unit z AllA = 1 2 IntA = 1 2 z BoolA = 1 z 2 NoneA = 1z 2 z TCS2002

  25. Encoding Subtyping Hierarchies (III) • Any finite hierarchy can be embedded in the powerset lattice of a set S • Better encodings for specific classes of hierarchies TCS2002

  26. Bounded Polymorphism • Extends both parametric polymorphism and subtyping • double: Int.   • toString: All.  string • plus: Int.(  )   • Provides a connection between type instantiation and subtyping • We can safely encode a restricted form of bounded polymorphism using a simple extension of our recipe TCS2002

  27. Formalization • Translation • From a language with a restricted form of bounded polymorphism • To a language with parametric polymorphism • Using the “recipe” given earlier • See paper for details TCS2002

  28. Conclusion • Use type equivalence to encode information in a free type variable • Use unification to enforce a particular relation on the information • Practical issues • complexity of types TCS2002

  29. TCS2002

  30. The Problem (II) datatype atom = I of int | B of bool fun mkI (i:int):atom = I(i) fun mkB (b:bool):atom = B(b) fun toString (v:atom):string = case v of I(i) => Int.toString(i) | B(b) => Bool.toString(b) fun double (v:atom):atom = case v of I(i) => I (2 * i) | _ => raise (Fail “type mismatch”) fun conj (v1:atom, v2:atom):atom = case (v1,v2) of (B(b1),B(b2)) => B (b1 andalso b2) | _ => raise (Fail “type mismatch”) TCS2002

  31. A Better Solution (II) type All = Int = Bool = unit datatype atom = I of int | B of bool fun mkI (i:int):Intatom = I(i) fun mkB (b:bool):Boolatom = B(b) fun toString (v:atom):string = case v of I(i) => Int.toString(i) | B(b) => Bool.toString(b) fun double (v:Intatom):Intatom = case v of I(i) => I (2 * i) | _ => raise (Fail “type mismatch”) fun conj (v1:Boolatom, v2:Boolatom):Boolatom = case (v1,v2) of (B(b1),B(b2)) => B (b1 andalso b2) | _ => raise (Fail “type mismatch”) TCS2002

  32. Bounded Polymorphism (I) • Extends both parametric polymorphism and subtyping • . • .() TCS2002

  33. Bounded Polymorphism (II) • IntA  IntC • Example: NatInt • double:Int.   • IntA  IntA •    where  = IntA • plus: Int.(  ) •      where  = IntA • plus (mkI 1, natToInt (mkN 2)) TCS2002

  34. Bounded polymorphism (III) • Limitations • Type variable bounds • ..()   •      where  = A and  = A • First-class polymorphism • Functional subtyping • (1  2).  2 •   2C where  = 1C  2A TCS2002

  35. Formalization (II) let f1 = 11 . x:1. c1 x in … let fn = nn . x:n. cn x in []  “safe” interface types TCS2002