Resources: The slides of this lecture were derived from [Järvi], with permission of the original author, by copy & x = 1 let x = 1 in... paste or by selection, annotation, or rewording. [Järvi] is in turn based on [Pierce] as the underlying textbook. x(1).!x(1) x.set(1) Programming Paradigms and Formal Semantics Lambda Calculi With Polymorphism Ralf Lämmel [Järvi] Slides by J. Järvi: Programming Languages, CPSC 604 @ TAMU (2009) [Pierce] B.C. Pierce: Types and Programming Languages, MIT Press, 2002 >1h
Polymorphism -- Why? What s the identity function? In the simple typed lambda calculus, this depends on the type! Examples λx:bool. x λx:nat. x λx:bool bool. x λx:bool nat. x... 194
Polymorphism Polymorphic function a function that accepts many types of arguments. Kinds of polymorphism Parametric polymorphism ( all types ) Bounded polymorphism ( subtypes ) Ad-hoc polymorphism ( some types ) System F [Girard72,Reynolds74] = (simply-typed) lambda calculus + type abstraction & application 195
Polymorphism Kinds of polymorphism Parametric polymorphism ( all types ) Bounded polymorphism ( subtypes ) Ad-hoc polymorphism ( some types ) 196
System F -- Syntax tax t ::=x v tt t[t ] v ::=λx :T.t ΛX.t T ::=X T T X.T Type application Type abstraction Polymorphic type 197
System F -- Typing rules T-Variable x : T Γ Γ x : T T-Abstraction Γ, x : T u : U Γ λx : T.u : T U T-Application Γ t : U T Γ tu: T Γ u : U T-TypeAbstraction Γ, X t : T Γ ΛX.t : X.T T-TypeApplication Γ t : X.T Γ t[t 1 ]:[T 1 /X ]T 198
System F -- Evaluation rules E-AppFun t 1 t 1 t 1 t 2 t 1 t 2 E-TypeApp E-TypeApp t 1 t 1 t 1 [T ] t 1 [T ] E-AppArg t t vt vt E-AppAbs (λx :T.t) v [v/x]t E-TypeAppAbs (ΛX.t)[T ] [T /X ]t 199
Type abstraction and application Evaluation E-TypeApp t 1 t 1 t 1 [T ] t 1 [T ] E-TypeAppAbs (ΛX.t)[T ] [T /X ]t Typing T-TypeAbstraction Γ, X t : T Γ ΛX.t : X.T T-TypeApplication Γ t : X.T Γ t[t 1 ]:[T 1 /X ]T Type variables are in the environment. Type variables are subject to (implicit) renaming. 200
Examples Term id =ΛX.λx :X.x id[bool] id[bool] true id true Type : X.X X : bool bool : bool type error There is no type-argument deduction at this point. 201
Instantiated with nat The doubling function double=λx.λf :X X.λx :X.f (f x) double_nat = double [nat] : (nat nat) nat nat Instantiated with nat nat double_nat_arrow_nat = double [nat nat] : ((nat nat) nat nat) (nat nat) nat nat Invoking double double [nat] (λx : nat.succ (succ x)) 5 * 9 202
Self application Not typeable in the simply-typed lambda calculus λx :?. x x Typeable in System F selfapp = λx : X.X X.x [ X.X X] x selfapp : ( X.X X) ( X.X X) 203
The fix operator (Y) Not typeable in the simply-typed lambda calculus Typeable in System F. fix : X.(X X) X Encodeable in System F with recursive types. fix =? See [TAPL] 204
Remember lists? (in the simply-typed lambda calculus) New type:... List T New syntax:... nil[t] const[t] t t isnil[t] t head[t] t tail[t] t New congruence rules, e.g.: New computation rules, e.g.: t 1 t 1 cons[t ] t 1 t 2 cons[t ] t 1 t 2 head[s] (cons[t ] v 1 v 2 ) v 1 New typing rules, e.g.: Γ t : List T Γ head[t ] t : T 205
Lists in System F Types of list operations nil : X. List X cons : X.X List X List X isnil : X.List X bool head : X.List X X tail : X.List X List X List T can be encoded. X. (T U U) U U (see [TAPL] Chapter 23.4; requires fix) 206
Meaning of forall In a universal type, X...., we quantify over all types. Predicative polymorphism X ranges over simple types. Polymorphic types are type schemes. Type inference is decidable. Impredicative polymorphism X also ranges over polymorphic types. Type inference is undecidable. type:type polymorphism X ranges over all types, including itself. Computations on types are expressible. Type checking is undecidable. 207
Limits of type schemes Consider the polymorphic identity function: id : X. X X id = ΛX.λx : X.x Use id to construct a pair of Boolean and String: pairid : (Bool, String) pairid = (id true, id true ) Abstract over id: pairapply : ( X. X X) (Bool, String) pairapply = λf : X. X X. (f true, f true ) Type application left implicit. Argument must be polymorphic! 208
Existential types A means for information hiding and abstraction. Remember predicate logic. x.p(x) ( x. P(x)) Existential types can be encoded as universal types; see [TAPL]. Syntax: { X, T} 209
vs. t of type X.T Logical view: t has value of type [S/X]T for any S. Operational view: t is a mapping from type S to a term of type [S/X]T. t of type { X, T} Logical view: t has value of type [S/X]T for some S. Operational view: t is a pair of a type S and a term u of type [S/X]T. S is hidden. Notation: { *S, u } 210
Constructing existentials { *S, u } { *S, u } should be considered a package (module). The type system makes sure that S is inaccessible from outside. Consider the following package: p = {*nat, {a = 1, b = λx:nat. pred x}} Multiple types make sense: { X, {a:x, b:x X} } { X, {a:x, b:x nat} } Existential types require programmer annotation. 211
Annotating existentials p = {*nat, {a = 1, b = λx:nat. pred x}} as { X, {a:x, b:x X}} p has type: { X, {a:x, b:x X}} p = {*nat, {a = 1, b = λx:nat. pred x}} as { X, {a:x, b:x nat}} p has type: { X, {a:x, b:x nat}} 212
Information hiding Packages with different representation types can have the same existential type. p1 = {*nat, {a = 1, b = λx:nat. iszero x}} as { X, {a:x, b:x bool}} p2 = {*bool, {a = false, b = λx:bool. if x then false else true}} as { X, {a:x, b:x bool}} 213
Unpacking existentials (Opening package, importing module) The existential becomes available. The representation type is not accessible. Only the capabilities of the existential type are accessible. Example: let {X,t} = p2 in (t.b t.a) * true : bool 214
Typing rules T-PackExistential Γ t :[U/X ]T Γ { U, t} as { X, T } : { X, T } T-UnpackExistential Γ t 1 : { X, T 12 } Γ, X, x : T 12 t 2 : T 2 Substitution checks that the abstracted type of t can be instantiated with the hidden type to the actual type of t. Only expose abstract type! Γ let {X, x} = t 1 in t 2 : T 2 215
Evaluation rules E-Unpack E-Pack t t { T, t} as U { T, t } as U t 1 t 1 let {X, x} = t 1 in t 2 let {X, x} = t 1 in t 2 E-UnpackPack let {X, x} =({ T, v} as U) in t 2 [T /X ][v/x]t 2 The hidden type is known to the evaluation, but the type system did not expose it; so t2 cannot exploit it. 216
Illustration of information hiding The representation type must not leak / must remain abstract. t = {*nat, {a = 1, b = λx:nat. iszero x} as { X, {a:x, b:x bool}}} let {X,x} = t in pred x.a // Type error! The type can be used in the scope of the unpacked package. let {X, x} = t in (λ y:x. x.b y) x.a * false : bool The type cannot be free in the resulting type: let {X, x} = t in x.a // Type error! 217
Polymorphism Kinds of polymorphism Parametric polymorphism ( all types ) Bounded polymorphism ( subtypes ) Ad-hoc polymorphism ( some types ) 218
What is subtyping anyway? We say S is a subtype of T. S <: T Substitutability (Liskov substitution principle): For each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2. Practical type checking: Any expression of type S can be used in any context that expects an expression of type T, and no type error will occur. 219
Why subtyping Function in near-to-c: void foo( struct { int a; } r) { r.a = 0; } Function application in near-to-c: struct K { int a; int b: } K k; foo(k); // error Intuitively, it is safe to pass k. Subtyping allows it. 220
Subsumption Subsititutability is captured with the subsumption rule: Γ t : U U <: T Γ t : T Adding this rules requires revisiting other rules. Subtyping is a crosscutting extension. 221
Subtyping in simplified setting Simply-typed lambda calculus + records Booleans integers Structural subtyping for records 222
Subtyping for records Order of fields does not matter. S-RecordPermutation {l i : T i i 1...n } is a permutation of {k j : U j j 1...n } {l i : T i i 1...n } <: {k j : U j j 1...n } Example: {key : bool, value : int} <: {value : int, key : bool} 223
Subtyping for records We can always add new fields in the end. S-RecordNewFields {l i : T i i 1...n+k } <: {l i : T i i 1...n } Example: {key : bool, value : int, map : int int} <: {key : bool, value : int} 224
Subtyping for records We can subject the fields to subtyping. S-RecordElements for each i T i <: U i {l i : T i i 1...n } <: {l i : U i i 1...n } Example: {field1 : bool, field2 : {val : bool}} <: {field1 : bool, field2 : {}} 225
General rules for subtyping Reflexivity T <: T Transitivity T <: U T <: V U <: V Example Prove that {a : bool, b : int, c : {l : int}} <: {c : {}} 226
Subtyping and functions Assume that a function f of the following type is expected: f :T U Then it is safe to pass an actual function g such that: g :T U T <: T (g expects less fields than f) U <: U (g gives more fields than f) 227
Subtyping and functions Function subtyping covariant on return types contravariant on parameter types T 2 <: T 1 U 2 <: U 1 T 1 U 2 <: T 2 U 1 228
Supertype of everything T ::=... top The most general type T <: top The supertype of all types 229
Remember type annotation? Syntax: t ::=... t as T Typing rule: Γ t : T Γ t as T : T Evaluation rules: t u t as T u as T v as T v 230
Annotation is up-casting Illustrative type derivation: Example:.. Γ t : U U <: T Γ t : T Γ t as T : T (λx :bool.{a = x, b = false}) true as {a : bool} 231
Type annotation with down-casting Typing rule: Γ t : U Γ t as T : T Potentially too liberal Evaluation rules: t u t as T u as T Runtime type check v : T v as T v 232
Typing rules so far T-Record for each i, Γ t i : T i Γ {l i = t i i 1...n } : {l i : T i i 1...n } T-Projection Γ t : {l i : T i i 1...n } Γ t.l j : T j T-Subsumption Γ t : U U <: T Γ t : T T-Variable x : T Γ Γ x : T T-Abstraction Γ, x : T u : U Γ λx : T.u : T U T-Application Γ t : U T Γ tu: T Γ u : U T-True true : bool T-False false : bool 233
Reminder A type system is a tractable syntactic method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute. [B.C. Pierce] 234
Violation of syntax direction Consider an application: t u where t of type U V and u of type S. Type checker must figure out that S <: U. This is hard with the rules so far. The rules need to be redesigned. 235
Analysis of subsumption The term in the conclusion can be anything. It is just a metavariable. T-Subsumption Γ t : U U <: T Γ t : T E.g. which rule should you apply here? Γ (λx :U.t) :? T-Abstraction or T-Subsumption? 236
Analysis of transitivity S-Transitivity T <: U T <: V U does not appear in conclusion. U <: V Thus, to show T <: V, we need to guess a U. For instance, try to show the following: {y :int, x :int} <: {x :int} 237
Analysis of transitivity What is the purpose of transitivity? Chaining together separate subtyping rules for records! S-RecordPermutation {l i : T i i 1...n } is a permutation of {k j : U j j 1...n } {l i : T i i 1...n } <: {k j : U j j 1...n } S-RecordElements for each i T i <: U i {l i : T i i 1...n } <: {l i : U i i 1...n } S-RecordNewFields {l i : T i i 1...n+k } <: {l i : T i i 1...n } 238
Algorithmic subtyping Replace all previous rules by a single rule. S-Record {l i i 1...n } {k j j 1...m } l i = k j implies U i <: T j e d need to prove: {k j : U j i 1...m } <: {l i : T i i 1...n } Correctness / completeness of new rule can be shown. Maintain extra rule for function types. } { S-Function T 1 <: T 2 U 1 <: U 2 T 2 U 1 <: T 1 U 2 239
Algorithmic subtyping The subsumption rule is still not syntax-directed. The rule is essentially used in function application. Express subsumption through an extra premise. Retire subsumption rule. T-Application Γ t : U T Γ u : V V <: U Γ tu: T 240
Summary: Lambdas with somewhat sexy types Done:,, <:,... Not done: μ,... Prepping: Types and Programming Languages Chapters 15, 16, 22, 23, 24 Lab: The Typed Lambda Calculus in Prolog Outlook: Functional programming with Haskell Denotational semantics 241