Types and Programming Languages
Lecture 10. Universal and existential types
Xiaojuan Cai
BASICS Lab, Shanghai Jiao Tong University
Fall, 2016
Coming soon
I We studied the simple form of let-polymorphism found in ML.
I We will consider a more general form of polymorphism:universal types in the setting of System F.
I We will find existential types very useful for data abstractionin programming languages.
I We also will study (very briefly) bounded quantifications whichare the mixture of universal (existential) types and subtyping.
Outline
Universal types
Existential typesData abstraction
Bounded quantification
Motivation
Can we write an infinite number of ”doubling” functions?
doubleNat=λf:Nat→Nat.λx:Nat.f(f x);
doubleRcd=λf:{l:Bool}→{l:Bool}.λx:{l:Bool}.f (f x);
doubleFun=λf:(Nat→Nat)→(Nat→Nat).λx:Nat→Nat.f(fx);
Abstraction principle. Where similar functions are carried out bydistinct pieces of code, it is generally beneficial to combine theminto one by abstracting out the varying parts.
Polymorphism
Polymorphism: a single piece of code to be used with multipletypes.
I Parametric polymorphism. Using variables in place of actualtypes, and then instantiated with particular types as needed.
I Ad-hoc polymorphism. Allowing a polymorphic value toexhibit different behaviors when “viewed” at different types,e.g., overloading
I Subtyping polymorphism. Giving a single term many typesusing the rule of subsumption.
For functional programmers, polymorphism is always parametricpolymorphism. However, for OO programmers, polymorphism isalways subtyping polymorphism, and they call parametricpolymorphism genericity.
System F [Girard 1972, Reynold 1974]System F = Polymorphic λ-calculus = second-order λ-calculusSystem F is a simply typed λ-calculus with type abstractions andtype applications (instantiations).
t ::= ... | λX .t | t[T ]
v ::= ... | λX .t
T ::= ... | ∀X .T
Γ ::= ... | Γ,X
E-TAppt1 −→ t ′1
t1[T2] −→ t ′1[T2]E-Tabs
(λX .t1)[T2] −→ [X 7→ T2]t1
T-TabsΓ,X ` t1 : T1
Γ ` λX .t1 : ∀X .T1T-Tapp
Γ ` t1 : ∀X .T1
Γ ` t1[T2] : [X 7→ T2]T1
Examples
We will see several examples to illustrate the expressive power ofSystem F.
I A polymorphic identity function:id = λX.λx : X.xid[Nat] 0
I A self-application, λx .xx :selfApp = λx : ∀X.X→ X. x[∀X.X→ X] x
Quiz.
I Give the definition of polymorphic doubling function.doubleNat=λf:Nat→Nat.λx:Nat.f(f x);
double = λX.λf:X→X.λx:X.f(f x)
I Try to type (λx .xx)(λx .xx) in System F.We can not type (λx .xx)(λx .xx) in System F.
Church encodings
I Church encodings can be carried out in System F.
I We can add booleans, nats, ... as primitives.
I System F is not Turing powerful.
Church booleans
I In untyped λ-calculus
tru = λt.λf .tfls = λt.λf .f
I In System F
CBool = ∀X .X → X → Xtru = λX .λt : X .λf : X .tfls = λX .λt : X .λf : X .f
Church pairs
I In untyped λ-calculus
pair = λf .λs.λb.b f sfst = λp.p tru
snd = λp.p fls
I In System F
Pair X Y = ∀R.(X → Y → R)→ Rpair = λX .λY .λf : X .λs : Y .λR.λb : (X → Y → R).b f s
fst = λX .λY .λp : Pair X Y .p[X ] (λf : X .λs : Y .f )snd = λX .λY .λp : Pair X Y .p[Y ] (λf : X .λs : Y .s)
Church numerals
I In untyped λ-calculus
0 = λs.λz .z1 = λs.λz .s z2 = λs.λz .s (s z)3 = λs.λz .s (s (s z))· · ·
I In System F
CNat = ∀X .(X → X )→ X → X0 = λX .λs : X → X .λz : X .z1 = λX .λs : X → X .λz : X .s z2 = λX .λs : X → X .λz : X .s (s z)
csucc = λn : CNat.λX .λs : X → X .λz : X .n[X ] s (s z)
List
I In untyped λ-calculus
list[x , y , z ] = λc .λn.c x (c y (c z n))nil = λc .λn.n
cons = λh.λt.λc .λn.c h (t c n)isnil = λl .l (λh.λt.fls) tru
I In System F
List X = ∀R.(X → R → R)→ R → Rnil = λX .λR.λc : X → R → R.λn : R.n
cons = λX .λh : X .λt : (List X ).λR.λc : X → R → R.λn : R.c h (t[R] c n)
isnil = λX .λl : (List X ).l [CBool ] (λh : X .λt : CBool .fls) tru
Properties of universal types
Theorem 23.5.1 [Preservation]: If Γ ` t : T and t −→ t, thenΓ ` t ′ : T.
Theorem 23.5.2 [Progress]: Suppose t is a closed, well-typedterm. Then either t is a value or else there is some t with t −→ t.
Theorem 23.5.3 [Normalization]: Well-typed System F termsare normalizing.
Erasure
erase(x) = xerase(λx : T1.t2) = λx .erase(t2)erase(t1 t2) = erase(t1) erase(t2)erase(λX .t2) = erase(t2)erase(t1[T2]) = erase(t1)
Type reconstruction problem. A term m in the untypedlambda-calculus is said to be typable in System F if there is somewell-typed term t such that erase(t) = m.
Theorem [Undecidability, Wells 1994]. Type reconstruction forSystem F is undecidable.
Fragments of System F
The lack of type reconstruction leads to various fragments ofsystem F with type reconstruction.
I let-polymorphism in SML
I rank-2 polymorphism, no path from root to the quantifierpasses to the left of 2 or more arrows, e.g.,(∀X.X→ X)→ Nat, but ((∀X.X→ X)→ Nat)→ Nat is notrank-2.
Universal types
Existential typesData abstraction
Bounded quantification
Motivation
I Since there are universal quantifiers in type systems, it isnatural to wonder whether existential quantifiers might alsobe useful in programming.
I The answer is “yes” and existential types offer an elegantfoundation for data abstraction.
Existential type
I We use {∃X ,T} to denote existential type.
I An element of existential type is a pair, written {∗S , t} whereS is a type and t has type [X 7→ S ]T .
I For example, {∗Nat, {a = 5, f = λx : Nat.succ(x)}} has type{∃X , {a : X , f : X → X}}, and it also has type{∃X , {a : X , f : X → Nat}}.
I User has to add annotations to tell the type checker about theexistential type by using ascription.
I The elements of a existential type are called packages.
Typing rules
I intro-rule:
T-PackΓ ` t2 : [X 7→ U]T2
Γ ` {∗U, t2} as {∃X ,T2} : {∃X ,T2}
I elimin-rule:
T-UnPackΓ ` t : {∃X .T}, Γ,X , x : T ` t2 : T2
Γ ` let {X , x} = t in t2 : T2
Evaluation rules
I computation-rule:
let {X , x} = ({∗T1, v1} as T ) in t2 −→ [X 7→ T1][x 7→ v1]t2
I congruence rules:
t1 −→ t ′1{∗T1, t1} as T −→ {∗T1, t
′1} as T
t1 −→ t ′1
let {X , x} = ({∗T1, t1} as T ) in t2−→ let {X , x} = ({∗T1, t
′1} as T ) in t2
Examples
Quiz. Please draw the type derivation tree of the following terms:
1. p4={*Nat, {a=0, f=λx:Nat.succ(x)}} as {∃X, {a:X,f:X→Nat}};
2. p5={*Bool, {a=true, f=λx:Bool.0}} as {∃X, {a:X,f:X→Nat}};
3. up1 = let {X,x}=p4 in (x.f x.a);
4. up2 = let {X,x}=p4 in succ(x.a);
Outline
Universal types
Existential typesData abstraction
Bounded quantification
Existential types and data abstraction
I We have seen that type systems can catch small-scaleprogramming errors like 2+true.
I Type systems also offer crucial support for programming inthe large.
I We will see the usage of existential types for abstraction.
Abstract Data Type, ADT
ADT counter =
type Counter
representation Nat
signature
new : Counter,
get : Counter→Nat,
inc : Counter→Counter;
operations
new = 1,
get = λi:Nat.i,inc = λi:Nat.succ(i);
counter.get (counter.inc counter.new);
ADT as existential type
counterADT =
{*Nat,new = 1,
get = λi:Nat.i,inc = λi:Nat.succ(i)}
as {∃Counter,{new: Counter,
get: Counter→Nat,
inc: Counter→Counter}};
ADT hiding implementations
counterADT =
{*{x:Nat},new = {x=1},get = λi:{x:Nat}.x.i,inc = λi:{x:Nat}.{x=succ(x.i)}}
as {∃Counter,{new: Counter,
get: Counter→Nat,
inc: Counter→Counter}};
Outline
Universal types
Existential typesData abstraction
Bounded quantification
Motivation
I Polymorphism + Subtyping?
I We can keep them orthogonal.
I However, it will be more interesting if we mix them in someways.
Coming soon.
I A simple illustrating example
I F<:
An illustrating example
I An identity function on records:f = λx:{a:Nat}.xra = {a = 0}rab = {a = 0, b = 0}
I With T-Sub, we can apply f to both ra and rab.
I However, the term (f rab).b will be ill-typed.
I What about a polymorphic f?f = λX.λx:X.x
I It also can be applied to both ra and rab. And (f rab).b iswell-typed.
An illustrating example, cont’d
I Neither works if we want to define f asf = λx :?.{orig=x, geta = x.a}
I Polymorphism + Subtyping = bounded quantification
I A solution to above example might be:f = λX<:{a:Nat}.λx:X.{orig=x, geta = x.a}
I Please refer to Figure 26-1 for full definition of F<:
About F<:
I Bounded and Unbounded Quantification
∀X .T = ∀X <: Top.T
I Quiz. Draw the type derivation tree for f rab.
I Type safety property holds for F<:.
Conclusion
I Polymorphism means a single piece of code to be used withmultiple types.
I We have parametric polymorphism (this lecture), ad-hocpolymorphism (overloading) and subtyping polymorphism(OO).
I System F = simply typed λ-calculus + type abstraction andapplication (universal types).
I Universal types are crucial for polymorphism.
I Existential types are crucial for data abstraction.
I Polymorphism + subtyping = bounded quantification (F<:).
Homework
I 23.4.1, 23.4.3 (offline part), 23.4.4, 23.4.6, 23.4.12, 24.2.2,