Intensional Polymorphism in Type-Erasure Semantics Karl Crary, Stephanie Weirich, Greg Morrisett Presentation by Nate Waisbrot Authors' background Part of Cornell University's TAL (Typed Assembly Language) group Creating intermediate languages to compile into TAL Three styles of polymorphism • Get a value and inspect its type – Easy and efficient, but not powerful • Pass types as first-class objects – Powerful, but slow and complicated for the compiler • Pass values which represent types – Best of both worlds Passing values • Recall the paper "Dynamically Typing in a Statically Typed Language" (Abadi, Cardelli, Pierce, and Plotkin) • Types are tied to values -- you can't have one without the other Dynamic types Dynamic(5 int) dynamic value f : dynamic dynamic dynamic function x:dynamic. typecase x of int … … … Passing types • Values are described by types • Types are described by kinds • We could keep going… (System F) Overview of System F .x:.x The polymorphic identity function . The type of the identity function iden [int] 5 Application of the identity function ..x:.y:. (x y) a pair function .. ( ) its type pair [int] [string] 0 “zero” application Overview of iML Start with System F, add the ability to work with types alone .. the pair-type function TypeTypeType the kind of the pair-type function pairT [int] [string] this gives us the type (int string) Now add the typecase construct: typecase [.int] int 0 substitute for and return an int iML syntax ::= Type | c ::= | int | cc | c c | :.c | c c | Typerec c(cint, c, c) ::= c | | | :. e ::= x | i | x:.e | fix f:.v | e e | <e,e> | e | :.v | e[c] | typecase [.] … v::= i | x:.e | fix f:.v | <v,v> | :.v Typing hierarchy kinds: Type types: int values: 5 TypeType intint 6 . x:int.x What's wrong with type passing? • Types must be kept separate from values – Doubles the type-checker's work – Compiling it down to TAL is hard • Language semantics require types to always be passed Solution: type representations • Make new type, "representation" • Get back all the simplicity of normal valuepassing • As a bonus, gain some abstraction Overview of type representations R(Rint,Rint) The representation of intint R( R(int)R(int) ) Its type Syntax of R ::= Type | c ::= | int | cc | c c | :.c | c c | R(c) | Typerec c(cint, c, c, cR) ::= c | | | :. | :. e ::= x | i | x:.e | fix f:.v | e e | <e,e> | e | :.v | e[c] | pack e as . hiding | unpack <,x> = e in e | Rint | R(e,e) | R(e,e) | RR(e) | typecase [.c] … v::= i | x:.e | fix f:.v | <v,v> | :.v | pack v as . hiding | Rint | R(v,v) | R(v,v) | RR(v) TypeToString: dynamic types typeToString : dynamicstring x:dynamic. typecase x of int "int" string "string" "function" × "<" + typeToString Dynamic( 1x) + "," + typeToString Dynamic( 2x) + ">" TypeToString: type-passing fix typeToString : :Type.string . :Type. typecase [.string] of int "int" string "string" typeToString [] + "" + typeToString [] × "<" + typeToString [] + "," + typeToString [] + ">" TypeToString: type representations fix typeToString : :Type.R()string . :Type.x:R(). typecase [.string] x of Rint "int" Rstring "string" R(x,y) as typeToString [] x + "" + typeToString [] y R×(x,y) as × "<" + typeToString [] x + "," + typeToString [] y + ">" Type erasure • A well-typed program in typed -calculus has an equivalent in untyped -calculus Typed: x:.x Untyped: x.x TypeToString: with types erased fix typeToString : :Type.R()string . :Type.x:R(). typecase [.string] x of Rint "int" Rstring "string" R(x,y) as typeToString [] x + "" + typeToString [] y R×(x,y) as × "<" + typeToString [] x + "," + typeToString [] y + ">" Type refinement • Do dead-code elimination based on the type of the representation • Propagate information about the type of an argument back through the function Monomorphic closure x:.y A function with a free variable Its type (if y has type ) We want to eliminate free variables f = ((x e): env.ye) <y> The closed function env.(( env) ) env Its type Polymorphic closure The same closed function, with type passing :Kind. env:Type. :. :=. (( env) ) env Closure with representations f’ = x:( R()). 2 x f’ : ( R()) f’’ = pack (f’’ R) as env.(( env) ) env hiding R() f’’ : env.(( env) ) env Summary • • • • Create a value to represent a type Pass the value, not the type Passing values is easy Knowing types at runtime is useful