Concepts of Programming Languages Polymorphism and Type Inference Lecturer: Gabriele Keller Tutor: Liam O’Connor University of New South Wales School of Computer Sciences & Engineering Sydney, Australia COMP 3161/9161 Week 8 Tuesday, 30 April 13
Concepts of Programming LanguagesPolymorphism and Type Inference
Lecturer: Gabriele KellerTutor: Liam O’ConnorUniversity of New South WalesSchool of Computer Sciences & EngineeringSydney, Australia
COMP 3161/9161 Week 8
Tuesday, 30 April 13
Parametric Polymorphism
• Example: swap the elements of a pair (in Haskell)
• What is swap’s type?★In Haskell:
★ in MinHs:
swap (x, y) = (y, x)
swap :: (a, b) -> (b, a)
letfun swapIntBool :: (Int, Bool) -> (Bool, Int) pair = (snd pair, fst pair)
letfun swapBoolInt :: (Bool, Int) -> (Int, Bool) pair = (snd pair, fst pair).....
obviously, not the way to go!
Tuesday, 30 April 13
Parametric Polymorphism in MinHs
• Parametric polymorphism:
★ a and b are type variables
• Using a polymorphic function:
★when a polymorphic function is applied to a concrete value, the type variables are instantiated:
★ instantiates type variable
‣ a to Int
‣ b to Bool
letfun swap :: (a, b) -> (b, a) pair = (snd pair, fst pair)
swap (1, True)
Tuesday, 30 April 13
Parametric Polymorphism
• Assuming explicit typing ★ introduction of type variables needs to be explicit★ instantiation of type variables needs to be explicit
• Type abstraction
• Type instantiation
evaluates to a monomorphic function:
Type a in
Type b in letfun swap :: ((a, b) -> (b, a)) pair = (snd pair, fst pair)
inst (Type a in
inst (Type b in letfun swap :: ((a, b) -> (b, a)) pair = (snd pair, fst pair) Bool)
Int)
letfun swap :: (Int, Bool) -> (Bool, Int) pair = (snd pair, fst pair)
Tuesday, 30 April 13
Parametric Polymorphism
• What is the type of this function?
• Universal quantification:
★ it is ∀a.∀b.(a,b) ➔ (b,a)
★written in Haskell (leading forall optional)
Type a in
Type b in letfun swap :: ((a, b) -> (b, a)) pair = (snd pair, fst pair)
forall a b. (a, b) -> (b, a)
Tuesday, 30 April 13
Polymorphic MinHS - Concrete Syntax
Polytypes σ ::= τ | ∀ t. σMonotypes τ ::= Bool | Int | τ1 -> τ2
Expressions e ::= v
| inst (e, τ)| letfun id1 ::(τ1 -> τ2) id2 = e
| Type t in e | ...
only monotypes here!
Tuesday, 30 April 13
Polymorphic MinHS
• Valid Types:
‣ make sure we have no free type variables
t ∈ Δ
Δ ⊢ t ok
Δ ⊢ ∀ t. σ okP
Δ ∪ {t} ⊢ σ okP t ∈ Δ
Δ ⊢ Bool ok Δ ⊢ Int ok Δ ⊢ τ1 ➔ τ2 ok
Δ ⊢ τ1 ok Δ ⊢ τ2 ok
Δ ⊢ σ ok
Δ ⊢ σ okP
Tuesday, 30 April 13
Polymorphic MinHS
• Typing rules
Δ ∪ {t}, Γ ⊢e : σ t ∉ Δ
Δ, Γ ⊢ Type (t.e ): ∀ t. σ
Δ, Γ ⊢ e : ∀ t. σ Δ ⊢ τ ok
Δ, Γ ⊢ Inst e τ : σ [t:= τ]
Tuesday, 30 April 13
Polymorphic MinHS
• Dynamic Semantics
Inst e τ ↦M Inst e’ τ e ↦M e’
Inst(Type(t.e)) τ ↦M e [t:= τ]
Tuesday, 30 April 13
Polymorphic MinHs
• Polymorphic MinHs with
★explicit introduction of type variables:
‣ Type a in letfun id :: (a -> a) x = x
★ explicit instantiation of type variables:
‣ inst(Type a in letfun id : (a->a) x = x,Bool)
:: ∀ a.a ➔ a
:: Bool ➔ Bool
Tuesday, 30 April 13
Polymorphic MinHs• Polymorphic functions are not first class citizens in MinHs, because we only
allow polytypes at the top level
★we can’t have a polymorphic function as return value
★we can’t have a function that demands a polymorphic function as argument value
• This restriction is not actually necessary for explicitly typed MinHs, since type checking would still work without (but it would be a problem for type inference)
Tuesday, 30 April 13
Polymorphic MinHs
• For which of the following types can we write total, terminating MinHs functions? (excluding error)
★∀ a. ∀ b.(a * b) ➔ (b * a)
★∀ a. ∀ b.(a + b) ➔ (b + a)
★∀ a. ∀ b.(a * b) ➔ a
★∀ a. ∀ b.(a + b) ➔ a
★∀ a. ∀ b.(a ➔ b) ➔ (b ➔ a)
★∀ a. ∀ b. ∀ c. ((a ➔ c) * (b ➔ c)) ➔ (a+b ➔c)
• The type constructors +, * , and ➔ correspond to the logical operators ∨,∧ and ⇒ . Types to theorems, and terminating programs to (constructive) proofs, and the type checker to a proof checker
✔
✔
✔
✔
✘
✘
Tuesday, 30 April 13
Principal Type
• Explicitly typed polymorphic languages are awkward to use
• We want the compiler to infer the type of an expression for us.
• What is the type of this function?
• Possible types
(1) Int* Int ➔ Int
(2) Int* Bool ➔ Int
(3) Int* (Int ➔ (Int + Bool)) ➔ Int
(4) ∀ a. Int* a ➔ Int
• Types (1) - (3) are instances of type (4)
letfun f x = (fst x) + 1
Tuesday, 30 April 13
Principal Type
• We write τ’≤ τ if τ’ is less general than τ, that is τ’ is an instance of τ
★Int* Int ➔ Int ≤ ∀ a. Int* a ➔ Int
★∀ a. Int* a ➔ Int ≤ ∀ a. ∀ b. b* a ➔ b
★∀ a. Int* a ➔ Int ≤ ∀ a. ∀ a. a* a ➔ a
★∀ a. a* a ➔ a ≤ ∀ a. ∀ b. b* a ➔ b
• We are interested in the most general type τ of the expression e such that e: τ’ implies τ’ ≤ τ
• This is called the principal type of the expression
Tuesday, 30 April 13
Implicitly Typed MinHs
• MinHs with the following changes:
★no type annotations for functions and type constructors (sum & product type)
★roll, unroll, rec not part of the language
‣ not possible with implicit typing
★no explicit type abstraction and instantiation
‣ Type and inst not part of the language
★Types of the build-in functions are part of the environment:
‣ Γ = {+: Int ➔ Int ➔ Int, fst: ∀ a. ∀ b.(a * b) ➔ a , ....}
★no overloading yet, e.g., == still only compares integers,
Tuesday, 30 April 13
Typing Rules
• Application, if-expression, variable and product rules stay the same:
Γ ⊢ e1 : τ1 ➔τ2 Γ ⊢ e2 : τ1
Γ ⊢ Apply e1 e2: τ2
Γ ⊢ e1 : τ1 Γ ⊢ e2 : τ2
Γ ⊢ Pair e1 e2 : τ1 * τ2
Γ ⊢ x : τx : τ ∈ Γ
Γ ⊢ If t1 t2 t3: τ
Γ ⊢ t1:Bool Γ ⊢ t2 : τ Γ ⊢ t3 : τ
Tuesday, 30 April 13
Typing Rules
• Inr and Inl introduce free type variables:
Γ ⊢ e1 : τ1
Γ ⊢ Inl e1 : τ1 + τ2
Γ ⊢ e2 : τ2
Γ ⊢ Inr e2 : τ1 + τ2
• Functions:
Γ∪{f : τ1 ➔τ2 , x : τ1 } ⊢ e : τ2
Γ ⊢Letfun( f.x.e): τ1 ➔τ2
could be any type
Tuesday, 30 April 13
Typing Rules• ∀ -introduction and elimination
Γ ⊢ e: ∀ t. τ Γ ⊢ e: τ [t:=τ’]
Γ ⊢ e : ∀ t. τ Γ ⊢ e: τ t ∉ TypeVars(Γ)
Tuesday, 30 April 13
Typing Rules
• Do the typing rules describe a type inference algorithm?★are they syntax directed?‣ no - ∀-introduction can always be applied
★can we view Γ and the expression as input, the type as output?‣ no - ∀-elimination rule may instantiate an expression to the wrong type!‣ no - function rule may introduce wrong type for x and f in environment
Γ ⊢ Apply Fst (Pair 1 True): Γ ⊢ Fst:Γ ⊢ Fst: ∀ a. ∀ b.(a * b) ➔ a
Γ ⊢ Pair 1 True: (Int*Bool)⋮
Γ ⊢ Letfun(f.x. (Plus x 1)): Γ∪{f:Bool ➔ Int , x : Bool } ⊢ Plus x 1:
(Bool*Bool) ➔ Bool
⋮
Tuesday, 30 April 13
Type Inference Algorithm
• Idea
★delay the instantiation of type variables until necessary
★“merge” required and computed argument type
★replace ∀-quantified variables by free, fresh variables
Γ ⊢ Apply Fst (Pair 1 True): Γ ⊢ Fst: (x * y) ➔ xΓ ⊢ Fst: ∀ a. ∀ b.(a * b) ➔ a
Γ ⊢ Pair 1 True: (Bool * Int)⋮
(x * y) ➔ x (Bool * Int) ➔ z
?
=
type of function we have type of function we need
[z :=Int] [y :=Int,x := Bool]
Tuesday, 30 April 13
Type Inference Algorithm
• In some cases, it is necessary to substitute variables on both sides:
or to replace variables with other variables
(Bool * x) =(y * Int)
(x * x) = (x * y)
?
?
[y :=Int,x := Bool] [y :=Int,x := Bool]
[y:=x] [y:=x]
Tuesday, 30 April 13
Unification
• A substitution S, with S τ = S τ’ is called a unifier of τ and τ’
• For the algorithm, we need the most general unifier (mgu)
• We write τ1 ∼ τ2 if S is an mgu of τ1 and τ2
• Examples:
★are there mgu’s for the following pairs of types?
S
(a *(a * a)) = (b * c) ?
Int = Bool ?
(a *(a * a)) = ((a * a) * a) ?
Tuesday, 30 April 13
Type Inference Algorithm
• Now back to our type inference algorithm:
Γ ⊢ x : τ [a1:=β1, ..... an:=βn]x : ∀ a1. .... ∀ an. τ ∈ Γ βi fresh
TΓ ⊢ e1 : τ1 T1TΓ ⊢ e2 : τ2
UT1T Γ ⊢ Apply e1 e2: Uα
T1 τ1 ∼ τ2 ➔αU
α fresh
T (Γ∪{ x : α1 }∪{ f : α2 } ) ⊢ e:τ T α2 ∼ T α1 ➔ τ
UTΓ ⊢Letfun( f.x.e): U (T α1 ➔ τ)α fresh
• Note• the rules are syntax directed• the environment and expression are input & unifier and type are output
U
Tuesday, 30 April 13
Type Inference
• Application example:
Γ ⊢ Apply Fst (1, True): U [ ] [ ] Int
Γ ⊢ Fst:
Fst: ∀ a. ∀ b.(a * b) ➔ a ∈Γ
(x* y) ➔ x Γ ⊢(1, True): (Int, Bool)
⋮(x* y) ➔ x (Int, Bool) ➔α∼
U
[ ] [ ]
where U = {α:=Int, y:=Bool,x:=Int]
TΓ ⊢ e1 : τ1 T1Γ ⊢ e2 : τ2
UT1T Γ ⊢ Apply e1 e2: Uα
T1 τ1 ∼ τ2 ➔αU
α fresh
Tuesday, 30 April 13
• Simple function example:
Type Inference
T (Γ∪{ x : α1 }∪{ f : α2 } ) ⊢ e:τ α2 ∼ T α1 ➔ τ
UTΓ ⊢Letfun( f.x.e): T α1 ➔ τα1 ,α2 fresh
U
Γ ⊢Letfun( f.x.(x, x)):
[α2 := α1 ➔ (α1, α1)][](Γ∪{ x : α1 }∪{ f : α2 } ) ⊢(x, x): (α1, α1) α2 ∼ [] (α1 ➔ (α1, α1))
α1, α2 fresh[α2:= α1 ➔ (α1, α1)] α1 ➔ (α1, α1)
Tuesday, 30 April 13
Type Inference
• Simple recursive function
T (Γ∪{ x : α1 }∪{ f : α2 } ) ⊢ e:τ α2 ∼ T α1 ➔ τ
UTΓ ⊢Letfun( f.x.e): T α1 ➔ τα1 ,α2 fresh
U
Γ ⊢Letfun( f.x.(App f x)): α1 ➔ α3[α1 ➔ α3/α2]
[(α1 ➔ α3)/α2](Γ∪{ x : α1 }∪{ f : α2 } ) ⊢ App f x: α3 α2 ∼ [α1 ➔ α3/α2] (α1 ➔ α3)
⋮ [α1 ➔ α3/α2]
[α1 ➔ α3/α2]
Tuesday, 30 April 13
Re-introducing the ∀-quantor
• None of the rules so far re-introduced the ∀-quantor
• Is this necessary at all?
• only necessary if we have let-bindings so polymorphic functions can be ‘exported’
let f = letfun g x = (x,x) in (f True, f 1)
let f x = (x,x) in (f True, f 1)
Tuesday, 30 April 13
Re-introducing the ∀-quantor
• Generalise over all variables which occur free in τ, but not in Γ
‣ Gen (Γ, τ) = ∀(TV(τ) \ TV(Γ)). τ
★Example:
‣ Gen ({x : a , y: Int}, (a,b) ➔ b) = ∀b. (a,b) ➔ b
T1 Γ ⊢ e1:τ T1 T2 Γ ⊢(Let e1 x.e2): τ’
T2 (T1Γ∪ x:Gen (T1Γ, τ)) ⊢ e2:τ’
Tuesday, 30 April 13
Type Inference
• Rules for Plus, Mult, Inl, and Inr, can be derived from their type in and the application rule
• The inference rules describe Robin Milner’s type inference algorithm W
• Returns the same typing scheme as the non-syntax directed rules discussed previously (modulo ∀-quantification)
Tuesday, 30 April 13
Unification
• Simple unification algorithm
‣ input: two type terms t1 and t2, ∀-quantified variables replaced by fresh, unique variables
‣ output: the most general unifier of t1 and t2 (if it exists)
Tuesday, 30 April 13
Unification
• Cases t1 and t2
★are both type variables v1 and v2
‣ if v1 = v2, return empty substitution‣ otherwise return [v1/v2]
★are both primitive types‣ if they are the same, return the empty substitution‣ otherwise, there is no unifier
★both are product types with t1 = (t11*t12) and t2 = (t21*t22)‣ compute the mgu S of t11 and t21
‣ compute the mgu S’ of S t12 and S t22
‣ return S ∪ S’★both function types, sum types (see product types)★only one is is type variable v, the other an arbitrary term t‣ if v occurs in t, there is no unifier (occurs check)‣ otherwise, return {v:= t}
★otherwise, there is no unifier
Tuesday, 30 April 13