phantom types and subtyping

Download Phantom Types and Subtyping

Post on 21-Jan-2016

37 views

Category:

Documents

0 download

Embed Size (px)

DESCRIPTION

Phantom Types and Subtyping. Matthew Fluet Riccardo Pucella Dept. of Computer Science Cornell University. The Setting (I). Modern strongly typed functional language Parametric polymorphism val id:    = fn x => x Type constraints val idInt: int  int = fn x => x - PowerPoint PPT Presentation

TRANSCRIPT

  • Phantom Types and SubtypingMatthew Fluet Riccardo PucellaDept. of Computer ScienceCornell University

    TCS2002

  • The Setting (I)Modern strongly typed functional languageParametric polymorphismval id: = fn x => xType constraintsval idInt: int int = fn x => xDatatypes and type constructorsdatatype tree = Leaf of | Node of tree tree

    TCS2002

  • The Setting (II)Modern strongly typed functional languageLimited expressibility at foreign function interfacesNo polymorphic typesNo user defined datatypesNo primitive notion of subtyping

    TCS2002

  • The Problemdatatype atom = I of Int | B of boolfun 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 errorconj (mkI 3, mkB true) run-time error

    TCS2002

  • Wish ListRaise compile-time type errors on domain violations rather than run-time errorstoString should apply to all atomsdouble should only apply to integer atomsconj should only apply to boolean atomsPreserve the implementationWould like to treat integer and boolean atoms as subtypes of all atoms

    TCS2002

  • A First Solution (I)type All, Int, Booldatatype atom = I of int | B of boolfun mkI (i:int):Int atom = ...fun mkB (b:bool):Bool atom = ...fun toString (v:All atom):string = ...fun double (v:Int atom):Int atom = ...fun conj (v1:Bool atom, v2:Bool atom):Bool atom = ...double (mkB true) compile-time type error; Int atom Bool atomconj (mkI 3, mkB true) compile-time type error; Bool atom Int atom

    toString (mkI 1) compile-time type error; Int atom All atomtoString (mkB false) compile-time type error; Bool atom All atom

    TCS2002

  • Phantom Typestype All, Int, Booldatatype atom = I of int | B of boolfun mkI (i:int):Int atom = ...fun mkB (b:bool):Bool atom = ...

    Phantom typesAbstract types that need not have any corresponding run-time valuesPhantom type variablesType instantiations of in atom do not contribute to the run-time representation of atoms

    TCS2002

  • A First Solution (II)type All, Int, Booldatatype atom = I of int | B of boolfun mkI (i:int):Int atom = ...fun mkB (b:bool):Bool atom = ...fun toString (v:All atom):string = ...fun double (v:Int atom):Int atom = ...fun conj (v1:Bool atom, v2:Bool atom):Bool atom = ...fun intToAll (v:Int atom):All atom = vfun boolToAll (v:Bool atom):All atom = v

    toString (intToAll (mkI 1)) 1 toString (boolToAll (mkB false)) false

    TCS2002

  • A Better Solutiontype All, Int, Booldatatype atom = I of int | B of boolfun mkI (i:int):Int atom = ...fun mkB (b:bool):Bool atom = ...fun toString (v: atom):string = ...fun double (v:Int atom):Int atom = ...fun conj (v1:Bool atom, v2:Bool atom):Bool atom = ...double (mkB true) compile-time type error; Int atom Bool atomconj (mkI 3, mkB true) compile-time type error; Bool atom Int atom

    toString (mkI 1) well typed; Int atom unifies with atomtoString (mkB false) well typed; Bool atom unifies with atom

    TCS2002

  • The Phantom Types TechniqueUse a superfluous type variable and type constraints to encode extra informationUnderlies many interesting uses of type systemsForeign function interfacesEmbedded languagesUncaught exception analysisA folklore technique

    TCS2002

  • ContributionsA general encoding of subtyping hierarchies into phantom typesA formalization of one use of the phantom types technique

    TCS2002

  • OutlineA recipe for interfaces and implementationsEncoding subtyping hierarchiesBounded polymorphismFormalization

    TCS2002

  • From Subtyping to PolymorphismFeatures of the exampleAn underlying primitive type of valuesA set of operationsA hierarchy of implicit subtypesmkI 1Intint atomtoStringAll string atom string

    TCS2002

  • The RecipeGiven:A primitive type p An implicit subtyping hierarchy 1,,n An implementation of p and its operationsDeriveA safe interface (the types)A safe implementation (the code)RestrictionsShared representation and operations

    TCS2002

  • Applying the RecipeGiven:A primitive type: atom An implicit subtyping hierarchy: All, Int, Bool An implementation: structure Atom DeriveA safe interface: signature SAFE_ATOMA safe implementation: structure SafeAtom

    TCS2002

  • Deriving the Interface (I)Introduce type Encode each implicit type as 1 unifies with 2 iff 1 2

    1C unifies with 2A iff 1 2Example:AllC = unitAllA = IntC = intIntA = intBoolC = boolBoolA = bool

    TCS2002

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

    TCS2002

  • 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 -> atomendsignature SAFE_ATOM = sig type atom val mkI: int -> IntC atom val mkB: bool -> BoolC atom val toString: AllA atom -> string val double: IntA atom -> IntC atom val conj: BoolA atom * BoolA atom -> BoolC atomend

    TCS2002

  • Applying the RecipeGiven:An abstract type: atom p An implicit subtyping hierarchy: All, Int, Bool p An implementation: structure Atom p DeriveA safe interface: signature SAFE_ATOMA safe implementation: structure SafeAtom

    TCS2002

  • Deriving the Implementation (I)Need a type isomorphic to pthe type system should consider 1 and 2 equivalent iff 1 and 2 are equivalentOpaque signature constraintHides all type implementation details

    TCS2002

  • 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.conjend

    TCS2002

  • Applying the RecipeGiven:An abstract type: atom p An implicit subtyping hierarchy: All, Int, Bool p An implementation: structure Atom p DeriveA safe interface: signature SAFE_ATOMA safe implementation: structure SafeAtom

    TCS2002

  • Encoding Subtyping Hierarchies (I)Powerset lattice encodingS = {s1,,sn} is a finite setOrdered by inclusion

    X SXC = t1 tnwhere ti =unitif si Xunit zotherwiseXA = t1 tn where ti =iif si Xi zotherwise

    TCS2002

  • Encoding Subtyping Hierarchies (II)AllC = unit unitIntC = unit unit zBoolC = unit z unitNoneC = unit z unit z

    AllA = 1 2IntA = 1 2 zBoolA = 1 z 2NoneA = 1 z 2 z

    TCS2002

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

    TCS2002

  • Bounded PolymorphismExtends both parametric polymorphism and subtypingdouble: Int. toString: All. stringplus: Int.( ) Provides a connection between type instantiation and subtypingWe can safely encode a restricted form of bounded polymorphism using a simple extension of our recipe

    TCS2002

  • FormalizationTranslation From a language with a restricted form of bounded polymorphismTo a language with parametric polymorphismUsing the recipe given earlierSee paper for details

    TCS2002

  • ConclusionUse type equivalence to encode information in a free type variableUse unification to enforce a particular relation on the informationPractical issuescomplexity of types

    TCS2002

  • TCS2002

  • The Problem (II)datatype atom = I of int | B of boolfun 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

  • A Better Solution (II)type All = Int = Bool = unitdatatype atom = I of int | B of boolfun mkI (i:int):Int atom = I(i)fun mkB (b:bool):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:Int atom):Int atom = case v of I(i) => I (2 * i) | _ => raise (Fail type mismatch)fun conj (v1:Bool atom, v2:Bool atom):Bool atom = case (v1,v2) of (B(b1),B(b2)) => B (b1 andalso b2) | _ => raise (Fail type mismatch)

    TCS2002

  • Bounded Polymorphism (I)Extends both parametric polymorphism and subtyping..()

    TCS2002

  • Bounded Polymorphism (II)Example: Nat Intdouble: Int.

    IntA IntC

    IntA IntA

    where = IntA

    plus: Int.( ) where = IntA plus (mkI 1, natToInt (mkN 2))

    TCS2002

  • Bounded polymorphism (III)LimitationsType variable bounds ..() where = A and = A

    First-class polymorphism

    Functional subtyping (1 2). 2 2C where = 1C 2A

    TCS2002

  • Formalization (II)

    let f1 = 11 . x:1. c1 x inlet fn = nn . x:n. cn x in[]safe interface types

    TCS2002

    In this talk, well use Standard ML, but similar techniques can be applied to Haskell or other languages.

    Use the phantom types technique to distinguish between all, integer and boolean atoms, using the abstract types All, Int, and Bool.Solves the problem with double and conj being applied to the wrong arguments, but toString cant be applied to Int and Bool atoms.We can introduce coercion functions, which are operationally the identity functio

Recommended

View more >