0% found this document useful (0 votes)
5 views22 pages

18-TypeCheck

The document discusses type checking in the context of formal methods for software engineering, particularly focusing on the λ-calculus and the introduction of primitive values and types to resolve ambiguities in expressions. It outlines the typing relation, application rules, and the process of type inference, emphasizing the importance of well-typed programs and the soundness of type systems. Additionally, it highlights the challenges of completeness in type systems and the ongoing quest for more expressive and complete type systems.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views22 pages

18-TypeCheck

The document discusses type checking in the context of formal methods for software engineering, particularly focusing on the λ-calculus and the introduction of primitive values and types to resolve ambiguities in expressions. It outlines the typing relation, application rules, and the process of type inference, emphasizing the importance of well-typed programs and the soundness of type systems. Additionally, it highlights the challenges of completeness in type systems and the ongoing quest for more expressive and complete type systems.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 22

Type Checking

COMP2600 — Formal Methods for Software Engineering

Clem Baker-Finch

Australian National University


Semester 2, 2009

COMP 2600 — Type Checking 1


Types

• With Church encoding, the representations of c0 and false are


α-equivalent (ie, differ only in the names of variables).

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.

COMP 2600 — Type Checking 2


Primitive Values

• The value (λ a b. b) has an ambiguous interpretation. It might be a Bool,


Integer, or general function.

• We can extend the λ-calculus with primitive values and types, so that the
interpretation of Booleans and Integers is no longer ambiguous.

true, false :: Bool

0, 1, 2, 3... :: Int

• Now false cannot be mistaken for 0 or vice-versa.

COMP 2600 — Type Checking 3


More Primitive Values

Unfortunately, as our primitive values are no longer represented by


lambda-terms, we cannot use the Church versions of the functions ‘succ’,
‘plus’, ‘and’, ‘or’, ‘not’ ... etc

We must also add these functions to our new system as primitives.

succ :: Int → Int


plus :: Int → Int → Int

isZero :: Int → Bool

not :: Bool → Bool

These type signatures become axioms in our type system.

COMP 2600 — Type Checking 4


The Typing Relation

Γ ` 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

COMP 2600 — Type Checking 5


Application

When evaluating a function application, the function and argument must


have appropriate types.

If they don’t, then the evaluation gets stuck before we reach normal form.

isZero :: Int → Bool

isZero 0 −→ true OK
isZero true −→ ??? STUCK
isZero (succ 5) −→ isZero 6 −→ false OK
0 isZero −→ ??? STUCK
isZero (isZero) −→ ??? STUCK

COMP 2600 — Type Checking 6


The Application Rule

Γ ` e1 :: τ11 → τ12 Γ ` e2 :: τ11


Γ ` e1 e2 :: τ12

• The application rule expresses the typing constraints we wish to place


on the two expressions e1 and e2 .

• As we’re applying e1 to e2 , the expression e1 must evaluate to a function.

• 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 .

COMP 2600 — Type Checking 7


Type Checking

We check the type of an expression by proving that it has some type.

The proofs are usually presented as Gentzen style proof trees, who’s
structure follows the syntax of the expression being checked.

0/ ` succ :: Int → Int 0/ ` 5 :: Int (App)


0/ ` isZero :: Int → Bool 0/ ` succ 5 :: Int (App)
0/ ` isZero (succ 5) :: Bool

In this proof each statement is either an axiom, or has been constructed with
the Application rule (App).

COMP 2600 — Type Checking 8


An Alternate Presentation

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)

4. 0/ ` isZero :: Int → Bool (Axiom)


5. 0/ ` isZero (succ 5) :: Bool (App 4 3)

This style is easier to write down, but makes it harder to see the proof’s
natural branching structure.

COMP 2600 — Type Checking 9


Type Errors

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.

0/ ` succ :: Int → Int 0/ ` true :: Bool (App)


0/ ` isZero :: Int → Bool 0/ ` succ true :: Int (App)
0/ ` isZero (succ true) :: Bool

Γ ` e1 :: τ11 → τ12 Γ ` e2 :: τ11


Γ ` e1 e2 :: τ12

COMP 2600 — Type Checking 10


Type Annotations

What is the type of the following expression?

λ 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

COMP 2600 — Type Checking 11


The Abstraction Rule

Γ, x : τ1 ` e2 :: τ2
Γ ` λ(x : τ1 ). e2 :: τ1 → τ2

• A λ-abstraction defines a function, so it has a function type.

• The annotation on the parameter gives the type of argument this


function can be applied to.

• The parameter variable x is likely to be free in the function body e2 , so


we must extend the type environment with its type.

COMP 2600 — Type Checking 12


Example

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

COMP 2600 — Type Checking 13


Summary of rules

x:τ ∈ Γ
(Var)
Γ ` x :: τ

Γ, x : τ1 ` e2 :: τ2
(Abs)
Γ ` λ(x : τ1 ). e2 :: τ1 → τ2

Γ ` e1 :: τ11 → τ12 Γ ` e2 :: τ11


(App)
Γ ` e1 e2 :: τ12

COMP 2600 — Type Checking 14


Type Inference

To apply the typing rules, we need type annotations on the parameters of all
λ-abstractions (and let-bindings) in our program.

These annotations are tedious to write.

Luckily, we can infer them automatically from an un-annotated program, and


type check it at the same time.

Step 1: Add fresh type variables to λ-abstractions in the program.

λ x. isZero (succ x)
⇒ λ(x : τx ). isZero (succ x)

COMP 2600 — Type Checking 15


Step 2: Extract type constraints from this annotated program.

τ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

COMP 2600 — Type Checking 16


Constraint Generation

τx (Var) Only needed if x is primitive, eg isZero


x τx = ...type for x...

τ3 (App)
@
τ1 τ2 τ1 = τ2 → τ3

τ1
(Abs)
λ (x : τ x )
τ2 τ1 = τx → τ2

COMP 2600 — Type Checking 17


Step 3: Solve constraints.

1. τsucc = Int → Int


2. τsucc = τx → τ3
3. τisZero = Int → Bool
4. τisZero = τ3 → τ2
5. τ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)

Step 4: Substitute into original program.

COMP 2600 — Type Checking 18


Soundness = Progress + Preservation

“Well typed programs don’t go wrong” – Milner


or
“If an expression is well typed, then its evaluation does not get stuck”

Progress:

If e is a well typed expression


then (e is in normal form or e can be evaluated further).

Preservation:

If (e has type τ and e evaluates to a new expression e0 )


then e0 has type τ

COMP 2600 — Type Checking 19


Completeness

“If the evaluation of an expression does not get stuck, then it is well typed.”

The evaluation of the diverging expression (λ x. x x) (λ z. z z) does not get


stuck. Can we work out its type?

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

COMP 2600 — Type Checking 20


No!

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.

This typing system is incomplete.

COMP 2600 — Type Checking 21


The Big Picture

• Static typing is fun and profitable!

• It’s better to know if your program will crash sooner rather than later!

• There is an ongoing (endless?) quest to find more complete and


expressive type systems.

• There is a fine balance between completness and the ability to do full


type inference.

• 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.

COMP 2600 — Type Checking 22

You might also like