18-TypeCheck
18-TypeCheck
Clem Baker-Finch
def
c0 = λs z. z
def
false = λx y. y
• If a term reduces to (λ a b. b) how will we know whether it should be
taken a Boolean, an Integer, or some other type of object?
• Notice how hard it is to define the word “type” without using that word, or
a synonym in the definition – this hints at how fundamental the idea is.
• We can extend the λ-calculus with primitive values and types, so that the
interpretation of Booleans and Integers is no longer ambiguous.
0, 1, 2, 3... :: Int
Γ ` e :: τ
“With type environment Γ, the expression e has type τ”
The type environment is a set which contains the types of all variables which
are free in the expression. (Γ = “gamma”, τ = “tau”)
The type of the expression depends on the types we assign to these free
variables, for example:
x : Bool ` x :: Bool
vs
x : Int ` x :: Int
If they don’t, then the evaluation gets stuck before we reach normal form.
isZero 0 −→ true OK
isZero true −→ ??? STUCK
isZero (succ 5) −→ isZero 6 −→ false OK
0 isZero −→ ??? STUCK
isZero (isZero) −→ ??? STUCK
• We’ve named the argument type τ11 . The function must accept an
argument of this type.
• Applying the function will generate a new value as the result. We’ve
named the type of this result τ12 .
The proofs are usually presented as Gentzen style proof trees, who’s
structure follows the syntax of the expression being checked.
In this proof each statement is either an axiom, or has been constructed with
the Application rule (App).
We could also lay out the proofs in a flat style, giving each statement and its
justifications in turn.
1. 0/ ` 5 :: Int (Axiom)
2. 0/ ` succ :: Int → Int (Axiom)
3. 0/ ` succ 5 :: Int (App 2 1)
This style is easier to write down, but makes it harder to see the proof’s
natural branching structure.
If there is a type error in the expression then we will not be able to construct
a valid proof tree.
The following proof is not valid because function and argument types of
(succ true) do not match. The application rule does not apply.
λ x. 5
Without knowing the type of the argument (and without polymorphism), there
is no way to tell. It could be Int → Int, Bool → Int or some other type.
We will add a type annotation to the parameter to make its type explicit.
λ(x : Bool). 5
Γ, x : τ1 ` e2 :: τ2
Γ ` λ(x : τ1 ). e2 :: τ1 → τ2
x : Int ∈ {x : Int}
(Var)
x : Int ` succ :: Int → Int x : Int ` x :: Int
x : Int ` isZero :: Int → Bool x : Int ` succ x :: Int (App)
x : Int ` isZero (succ x) :: Bool
(Abs)
/0 ` λ(x : Int). isZero (succ x) :: Int → Bool
x:τ ∈ Γ
(Var)
Γ ` x :: τ
Γ, x : τ1 ` e2 :: τ2
(Abs)
Γ ` λ(x : τ1 ). e2 :: τ1 → τ2
To apply the typing rules, we need type annotations on the parameters of all
λ-abstractions (and let-bindings) in our program.
λ x. isZero (succ x)
⇒ λ(x : τx ). isZero (succ x)
τ1
τsucc = Int → Int (axiom)
λ (x : τ x ) τsucc = τx → τ3 (from use in program)
τ2
@ τisZero = Int → Bool (axiom)
τ3 τisZero = τ3 → τ2 (from use in program)
isZero @
τ1 = τx → τ2 (from λ-abstraction)
succ x
τ3 (App)
@
τ1 τ2 τ1 = τ2 → τ3
τ1
(Abs)
λ (x : τ x )
τ2 τ1 = τx → τ2
6. τx = Int (Unify 1 2)
7. τ3 = Int (Unify 1 2)
8. τ2 = Bool (Unify 3 4)
9. τ1 = Int → Bool (Substitute 5 6 8)
Progress:
Preservation:
“If the evaluation of an expression does not get stuck, then it is well typed.”
W RONG x : τx ∈ {x : τx }
(Var)
x : τx ` x :: τx → τ2 x : τx ` x :: τx
(App) ..
x : τx ` x x :: τ2 .
(Abs)
0/ ` (λ(x : τx ). x x) :: τx → τ2 0/ ` (λ(z : τz ). z z) :: τx
(App)
0/ ` (λ(x : τx ). x x) (λ(z : τz ). z z) :: τ2
To assign a type to (x x) with this system we would need to solve the type
constraint: τx = τx → τ2
τx = τx → τ2
≡ τx = (τx → τ2 ) → τ2
≡ τx = ((τx → τ2 ) → τ2 ) → τ2
≡ τx = (((τx → τ2 ) → τ2 ) → τ2 ) → τ2
≡ τx = (((· · · → τ2 ) → τ2 ) → τ2 ) → τ2
Our system has no way of representing infinite/graphical types like this one.
We cannot assign a type to all expressions which do not get stuck during
evaluation.
• It’s better to know if your program will crash sooner rather than later!
• More complete type systems often sacrifice the ability to perform full type
inference, requiring (some) type annotations to be added to the program.
• The type system for Haskell98 is sound, and supports full inference.