






Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
An introduction to type inference in the context of simply typed lambda calculus. It covers the basics of type environments, type judgments, and type rules. The document also includes examples of type checking and the algorithm for type checking. Additionally, it discusses product types, sum types, recursive types, and folding and unfolding. The document concludes by discussing the benefits and drawbacks of type inference.
Typology: Study notes
1 / 11
This page cannot be seen from the preview
Don't miss anything!







Type Systems CMSC 631 – Program Analysis and Understanding Fall 2003 CMSC 631, Fall 2003 2
■ (^) false = λx.λy.x ■ (^) 0 (Scott) = λx.λy.x
■ (^) So we can easily misuse combinators
CMSC 631, Fall 2003 3
■ Good programs = well typed ■ Bad programs = ill typed or not typable
■ (^) 0 + 1 // well typed ■ (^) false 0 // ill-typed: can’t apply a boolean ■ 1 + (if true then 0 else false) // ill-typed: can’t add boolean to integer
CMSC 631, Fall 2003 4
■ Functions include the type of their argument ■ We don’t really need this, but it will come in handy
■ t1 → t2 is a the type of a function that, given an argument of type t1, returns a result of type t
■ (^) A e : t ■ (^) “In type environment A, expression e has type t”
CMSC 631, Fall 2003 7
■ ෘ is the empty type environment
CMSC 631, Fall 2003 8
A n : int x dom(A) A x : A(x) A, x:t e : t′ A λx:t.e : t→t′ A e1 : t→t′ A e2 : t A e1 e2 : t CMSC 631, Fall 2003 9
■ (^) For each syntactic form, only one possible rule ■
■ (^) TypeCheck : type env × expression → type TypeCheck(A, n) = int TypeCheck(A, x) = if x in dom(A) then A(x) else fail TypeCheck(A, λx:t.e) = TypeCheck((A, x:t), e) TypeCheck(A, e1 e2) = let t1 = TypeCheck(A, e1) in let t2 = TypeCheck(A, e2) in if dom(t1) = t2 then range(t1) else fail
■ (^) Notice that the last rule requires that e1 is a function
(λx.e1) → l^ (λx.e1) e1 → l^ λx.e e[e2\x] → l^ e′ e1 e2 → l^ e′ n → l^ n
CMSC 631, Fall 2003 19
■ (^) It would require a type t such that t = t→t′
■ Every program has a normal form ■ I.e., every program halts!
A, x:? x : t t A, x:? x : t A, x:? x x : ... A λx:?.x x : ... CMSC 631, Fall 2003 20
■ (^) We define the type μα.t to be the solution to the (recursive) equation α = t ■ (^) Example: μα.int→α
→ int int int int → → → or → int CMSC 631, Fall 2003 21
■ Standard unification, omit occurs checks ■
■ (^) The programmer puts in explicit fold and unfold operations to expand/contract one “level” of the type trees
→ int → int int → unfold fold CMSC 631, Fall 2003 22
■ (Pure = variables, functions, applications only)
■ E.g., for data structures like lists, tree, etc. ■
■ (^) E.g., struct foo { int x; struct foo *next; } is different from struct bar { int x; struct bar *next; }
CMSC 631, Fall 2003 25
■ Note: in ML this type is written t ref
A e : t A ref e : ref t A e : ref t A !e : t A e1 : ref t A e2 : t A e1 := e2 : t CMSC 631, Fall 2003 26
■ e ::= ... | () ■ t ::= ... | unit
A e1 : ref t A e2 : t A () : unit A e1 := e2 : unit CMSC 631, Fall 2003 27
■ (^) State is a map from locations to values ■ (^) Our redexes will be tuples ‹State, expression› ■ (^) As a consequence, order of evaluation matters
■ v ::= x | λx.e ■ (^) e ::= v | e e | ref e | !e | e := e
CMSC 631, Fall 2003 28
‹S, e› → ‹S′, v› loc fresh ‹S, ref e› → ‹S[v\loc], loc› ‹S, (λx.e1)› → ‹S, (λx.e1)› ‹S, e1› → S , v1› ‹S , e2› → S , v2› ‹S, e1; e2› → S , v2›
‹S, e1› → S , λx.e› S , e2› → S , v› S ,e[v\x]› → S , v′› ‹S, e1 e2› → S , v′› ‹S, e› → ‹S′, loc› ‹S, !e› → ‹S′, S′(loc)› ‹S, e1› → ‹S′, loc› ‹S′, e2› → ‹S′′, v› ‹S, e1 := e2› → ‹S′′[v\loc], v›
■ (^) Integers, functions, pairs, unions ■ (^) Extensions for recursive types and updatable refs ■
■ Type checking is straightforward (needs annotations) ■ Well typed programs don’t go “wrong”
CMSC 631, Fall 2003 37
■ (^) But that can be awkward to implement
CMSC 631, Fall 2003 38
■ (^) The terms are in a union-find forest ■ (^) When a variable and a term are equated, we union them so they have the same ECR ■ Note: Only need to maintain ECR of variables, not of all terms, though doing terms as well has some potential advantages
CMSC 631, Fall 2003 39
α γ α=int→β γ =int→int α= γ β
int int
int CMSC 631, Fall 2003 40
■ Original algorithm due to Robinson
■ Any other valid type is “more specific,” e.g.,
■ (^) α stands for “some particular type, but it doesn’t matter exactly which type it is”
■ (^) The identity function works for any argument type
■ (^) λx.x : α α→α ■ (^) For any type α, the identity function has type α→α ■ (^) This is also known as parametric polymorphism
CMSC 631, Fall 2003 43
■ For now, the programmer specifies this by hand ■ (^) (λx.x)[S] : S → S ■ (λx.x)[T] : T → T
■ (^) The type α α→α is a “function” in the domain of types, and it is passed a parameter at instantiation time ■ Sometimes this type is written α α→α
CMSC 631, Fall 2003 44
■ So just like with lambda calculus, we need to worry about free variables and capture-free substitution
■ FV(c) = ■ (^) FV(t→t′) = FV(t) FV(t′) ■ (^) FV( α.t) = FV(t) - {α}
CMSC 631, Fall 2003 45
■ (^) α[u\α] = u ■ (^) β[u\α] = β where β≠α ■ (^) (t→t′)[u\α] = t[u\α]→t′[u\α] ■ ( β.t)[u\α] = β.(t[u\α]) where β≠α and β FV(u) ■
CMSC 631, Fall 2003 46
■ (^) That’s what the for all means!
A e : α.t A e[t ] : t[t \α]
■ There is no interaction with the outside environment ■ Thus we can generalize the type of x
A, x:α e : α A λx.x : α→α A, x:int x : int A λx.x : int→int A, x:(i→i) x : (i→i) A λx.x : (i→i)→(i→i)
CMSC 631, Fall 2003 55
■ (^) e ::= n | x | λx.e | e e | let x = e in e ■ (^) s ::= t | α.s
CMSC 631, Fall 2003 56
A n : int A, x:α e : t′ α fresh A λx.e : α→t′ A e1 : t 1 A e2 : t t1 = t2 →β β fresh A e1 e2 : β CMSC 631, Fall 2003 57
A(x) = α.t β fresh A x : t[β\α] A e1 : t1 A,x: α.t e2 : t2 α A let x = e1 in e2 : t → → → → → (^) → CMSC 631, Fall 2003 58
let x = λx.x in // x : α.α→α x 3; // x : β→β, β=int x (λy.y) // x : γ→γ, γ=δ→δ
■ (^) e ::= x | n | λx.e | e e | ref e | !e | e := e ■ (^) s ::= t | α.s ■ (^) t ::= α | int | t → t | ref t
A e1 : t1 A,x: α.t e2 : t2 α A let x = e1 in e2 : t → →
CMSC 631, Fall 2003 61
let r = ref (λx.x) in // r : α.ref (α→α) r := λx.x+1; // checks; use r at ref (int → int) (!r) true // oops! checks; use r at ref(bool →bool)
CMSC 631, Fall 2003 62
■ (^) v ::= x | n | λx.e ■ e ::= v | e e | ref e | !e | e := e ■ ■ ■ ■ ■ (^) Intuition: Values cannot later be updated ■ (^) This solution due to Wright and Felleisen
A v : t1 A,x: α.t e2 : t2 α A let x = v in e2 : t
■ (^) Set of types is unlimited
■ (^) Types are the same at all program points ■ (^) May produce coarse results ■ (^) Type inference failure can be hard to understand
■ Exponential in worst case ■ Seems fine in practice (witness ML)