phantom types and subtyping

Post on 21-Jan-2016

59 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

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 Subtyping

Matthew Fluet Riccardo Pucella

Dept. of Computer ScienceCornell University

TCS2002 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 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 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, 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 atom

conj (mkI 3, mkB true) compile-time type error; Bool atom Int atomtoString (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, Booldatatype atom = I of int | B of boolfun mkI (i:int):Int atom = ...fun mkB (b:bool):Bool atom = ...

• 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, 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 9

A Better Solution

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: 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 atom

conj (mkI 3, mkB true) compile-time type error; Bool atom Int atomtoString (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

From Subtyping to Polymorphism

• 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

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)

• Introduce type • Encode each implicit type as

– 1 unifies with 2 iff 1 2

– 1C unifies with 2A iff 1 2

• Example:AllC = unit AllA = IntC = int IntA = int

BoolC = bool BoolA = 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 -> atomend

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

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 SXC = t1 … tn where ti = unit if si X

unit z otherwiseXA = t1 … tn where ti = i if si X

i z otherwise

TCS2002 24

Encoding Subtyping Hierarchies (II)

AllC = unit unit

IntC = unit unit z

BoolC = unit z unit

NoneC = unit z unit z

AllA = 1 2

IntA = 1 2 zBoolA = 1 z 2

NoneA = 1 z 2 z

All = {s1, s2}

Int = {s1} Bool = {s2}

None = {}

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 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 31

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 32

Bounded Polymorphism (I)

• Extends both parametric polymorphism and subtyping . .()

TCS2002 33

• IntA IntC

Bounded Polymorphism (II)

• Example: Nat Int– double: Int.

• IntA IntA • where = IntA

– plus: Int.( )• where = IntA • 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

• 2C where = 1C 2A

TCS2002 35

Formalization (II)

let f1 = 11 . x:1. c1 x in

…let fn = nn . x:n. cn x in

[]

“safe” interface types

top related