Download Type System, Type Judgments, Type Rules - Slide Notes | CMSC 631 and more Study notes Computer Science in PDF only on Docsity!
Type Systems CMSC 631 – Program Analysis and Understanding Fall 2007 CMSC 631 2
- Not all programs accepted by a language’s
grammar are actually defined (e.g., they do not
have a normal form):
■ (1 (λx. λy. x y)) ■ The (app) rule expects a function as the first argument, but statement expects a list, but here it has been given a numeral. There is no rule to evaluate such a program, so we’re “stuck.”
- It would be great to rule out such non-sensical
programs in advance, so we can a program can
never reach a “stuck state.”
The Need for a Type System
CMSC 631 3
- A type system is some mechanism for distinguishing
good programs from bad
■ Good programs = well typed ■ Bad programs = ill typed or not typable
- Examples: ■ 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 What is a Type System? CMSC 631 4
- “A type system is a tractable syntactic method
for proving the absence of certain program
behaviors by classifying phrases according to the
kinds of values they compute.”
■– Benjamin Pierce, Types and Programming Languages A Definition of Type Systems
CMSC 631 7
- A type environment (a.k.a. context ) is a map from
variables to types (a kind of symbol table)
is the empty type environment
- A closed term e is well-typed if ⊢ e : t for some t
- We’ll abbreviate this as ⊢ e : t ■ A, x:t is just like A, except x now has type t
- The type of x in A, x:t is t
- The type of z≠x in A, x:t in the type of z in A
- When we see a variable in a program, we look in the
type environment to find its type
■ All of this is similar to the store s we’ve been using for the language of commands, but here is applied to typing Type Environments CMSC 631 8 Type Rules 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 9 Example
- dom(A) A ⊢ - : int→int A ⊢ 3 : int A ⊢ - 3 : int A = - : int→int CMSC 631 10 Another Example
- dom(B) x dom(B) B ⊢ 3 : int A ⊢ 4 : int B ⊢ + : i→i→i B ⊢ x : i B ⊢ + x : int→int B ⊢ + x 3 : int A ⊢ (λx:int.+ x 3) : int→int A ⊢ (λx:int.+ x 3) 4 : int A = + : int→int→int B = A, x : int We’d usually use infix x + 3
CMSC 631 13 Progress
- Suppose ⊢ e : t. Then either e is a value, or there
exists e’ such that e → e′
- Proof by induction on e ■ Base cases n, λx:t.e – these are values, so we’re done ■ Base case x – can’t happen (empty type environment) ■ Inductive case e1 e2 – If e1 is not a value, then by induction we can evaluate it, so we’re done, and similarly for e2. Otherwise both e1 and e2 are values. Inspection of the type rules shows that e1 must have a function type, and therefore must be a lambda since it’s a value. Therefore we can make progress. CMSC 631 14 Preservation
- If A ⊢ e : t and e → e′ then A ⊢ e′ : t
- Proof by induction on e ■ Base cases n, x, λx:t.e – Impossible, since these terms don’t reduce
- But: what if we were using the nondeterministic semantics? ■ Induction. Assume A ⊢ e1 e2 : t and e1 e2 → e′. Then we have A ⊢ e1 : t′ → t and A ⊢ e2 : t′. (Why?) ■ Then there are three cases.
- If e1 → e1′ then by induction A ⊢ e1’ : t′ → t, so e1′ e2 has type t by the typing rule for applications
- If reduction inside e2, similar
CMSC 631 15 Preservation, cont’d
- Otherwise (λx.e) v → e[v\x]. Then we have ■ Thus we have - A, x : t′ ⊢ e : t - A ⊢ v : t′ ■ Then by the substitution lemma (next slide) we have - A ⊢ e[v\x] : t ■ And so we have preservation A, x: t′ ⊢ e : t A ⊢ λx.e : t′→t CMSC 631 16 Substitution Lemma
- If A ⊢ v : t and A, x:t ⊢ e : t′, then A ⊢ e[v\x] : t′
- Proof: Induction on the structure of e
- For the lazy semantics, we’d have to prove
something stronger
■ If A ⊢ e1 : t and A, x:t ⊢ e : t′, then A ⊢ e[e1\x] : t′
CMSC 631 19
e | inR
t
e
- | (case e of x1:t1 → e1| x2:t2 → e2) Sum Types (Tagged Unions) A ⊢ e : t A ⊢ inL t e : t1 + t A ⊢ e : t A ⊢ inR t e : t1 + t A ⊢ e : t1 + t A, x1:t1 ⊢ e1 : t A, x2:t2 ⊢ e2 : t A ⊢ (case e of x1:t1 → e1 | x2:t2 → e2) : t CMSC 631 20
- Self application is not checkable in our system ■ It would require a type t such that t = t→t′
- (We’ll see this next, but so far...)
- The simply-typed lambda calculus is strongly
normalizing
■ Every program has a normal form ■ I.e., every program halts! Self Application and Types A, x:? ⊢ x : t→t′ A, x:?^ ⊢^ x : t A, x:? ⊢ x x : ... A ⊢ λx:?.x x : ...
CMSC 631 21
- We can type self application if we have a type to
represent the solution to equations like t = t→t′
■ We define the type μα.t to be the solution to the (recursive) equation α = t ■ Example: μα.int→α Recursive Types or CMSC 631 22
- We can check type equivalence with the previous
definition
■ Standard unification, omit occurs checks
- Alternative solution: ■ The programmer puts in explicit fold and unfold operations to expand/contract one “level” of the type trees - unfold μα.t = t[μα.t\α] - fold t[μα.t\α] = μα.t Folding and Unfolding unfold fold
CMSC 631 25 ML Datatypes Example
- type list = Int of int | Cons of int * int list ■ Equivalent to μα.int+(int × α)
- (Int 3) equivalent to ■ fold (inLint×μβ.int+(int×β) 3)
- (Cons (2,(Int 3)) equivalent to ■ fold (inRint (2, fold (inLint×μβ.int+(int×β) 3)))
- match e with Int x -> e1 | Cons x -> e2 same as ■ case (unfold e) - x:int → e - | x: int×(μβ.int+(int×β)) → e CMSC 631 26
- In the pure lambda calculus, every term is typable
with recursive types
■ (Pure = variables, functions, applications only)
- Most languages have some kind of “recursive” type ■ E.g., for data structures like lists, tree, etc.
- However, usually two recursive types that define
the same structure but use a different name are
considered different
■ E.g., struct foo { int x; struct foo *next; } is different from struct bar { int x; struct bar *next; } Discussion
CMSC 631 27
- We’ve discussed simple types so far ■ Integers, functions, pairs, unions ■ Extensions for recursive types
- Type systems have nice properties ■ Type checking is straightforward (may need annotations) ■ Well typed programs don’t go “wrong” - They don’t get stuck in the operational semantics
- But...We can’t type check all good (untyped) lambda
calculus programs
■ Can you come up with an example? Recap CMSC 631 28
- How can we build more flexible type systems? ■ More programs type check ■ Type checking is still tractable
- How can reduce the annotation burden? ■ Type inference Up Next: Improving Types
CMSC 631 31
• Polymorphic functions map types to terms
■Normal functions map terms to terms
• Examples
■Λα.λx:α.x : α.α→α
■Λα.Λβ.λx:α.λy:β.x : α. β.α→β→α
■Λα.Λβ.λx:α.λy:β.y : α. β.α→β→β
Defining Polymorphic Functions
CMSC 631 32
• When we use a parametric polymorphic type, we
apply (or instantiate) it with a particular type
■ In System F this is done by hand: ■ (Λα.λx:α.x)[t1] : t1 → t ■ (Λα.λx:α.x)[t2] : t2 → t
• This is where the term parametric comes from
■ The type α.α→α is a “function” in the domain of types, and it is passed a parameter at instantiation time
Instantiation
CMSC 631 33
- Notice that there are no constructs for
manipulating values of polymorphic type
■ This justifies instantiation with any type - that’s what the forall means!
- Note also that we are adding α to A; we could
(should?) use this to ensure types are well-
formed
Type Rules A ⊢ e : α.t A ⊢ e[t′] : t[t′\α] A,α ⊢ e : t A ⊢ Λα.e : α.t CMSC 631 34
- We have to extend substitution to include types;
that’s up next …!
Small-step Semantics Rules
e → e’
(Λα.e)[t] → e[t\α] e[t] → e’[t]
(type-app) (^) (tapp-cong)
CMSC 631 37
- Let’s consider the simply typed lambda calculus
with integers
■ e ::= n | x | λx.e | e e ■ (No parametric polymorphism)
- Type inference : Given a bare term (with no type
annotations), can we reconstruct a valid typing
for it, or show that it has no valid typing?
■ Notice that lambda terms above have no type annotation Type Inference CMSC 631 38
- Problem: Consider the rule for functions
- Without type annotations, where do we get t? ■ We’ll use type variables for as-yet-unknown types - t ::= α | int | t → t ■ We’ll generate equality constraints t = t among the types and type variables - And then we’ll solve the constraints to compute a typing Type Language A, x:t ⊢ e : t′ A ⊢ λx:t.e : t→t′
CMSC 631 39 Type Inference Rules A ⊢ n : int x dom(A) A ⊢ x : A(x) A, x:α ⊢ e : t′ α fresh A ⊢ λx.e : α→t′ A ⊢ e1 : t 1 A ⊢ e2 : t t1 = t2 →β β fresh A ⊢ e1 e2 : β
“Generated” constraint
CMSC 631 40
- We collect all constraints appearing in the derivation
into some set C to be solved
- Here, C consists of one constraint α→α = int →β ■ Solution: α = int = β
- Thus this program is typable, and we can derive a
typing by replacing α and β by int in the proof tree
Example A, x:α ⊢ x:α A ⊢ (λx.x) : α→α A ⊢ 3 : int α→α = int →β A ⊢ (λx.x) 3 : β