Type Correctness Type Correctness Contracts provide signature precondition

  • Slides: 70
Download presentation
Type Correctness

Type Correctness

Type Correctness • Contracts provide signature, precondition etc. • It says nothing about implementation

Type Correctness • Contracts provide signature, precondition etc. • It says nothing about implementation • Program correctness deal with proving that implementation satisfies contract.

Program Correctness • Type correctness – Verify that the types of expressions in the

Program Correctness • Type correctness – Verify that the types of expressions in the program are “correct” – well-typing – E. g. + is applied to numbers – In other languages: we should also check that the type of value stored in a variable correspond to the variable declared type • Program Verification – Verify that the program halts and produces the “correct” output – Somewhat easier with design-by-contract, where it can be done in a modular fashion

Static/Dynamic Type Check • Static – Based on program code – can be applied

Static/Dynamic Type Check • Static – Based on program code – can be applied off-line • Dynamic – Needs concrete data – done at runtime

Static Type Inference • We will see 2 algorithms: – Type inference rules –

Static Type Inference • We will see 2 algorithms: – Type inference rules – Type equations

Type Checking / Inference • Infer the type of an expression. • In other

Type Checking / Inference • Infer the type of an expression. • In other words, we associate an expression e with a type t such that the evaluation of e yields a value in t. • The purpose is to guarantee type safety.

Languages and Types How to include type information ? • Fully typed (every value

Languages and Types How to include type information ? • Fully typed (every value has a type) – C, Pascal, Java. . • Semi-typed (allow typeless structures of values) – Scheme • Untyped – Prolog

How Types are Specified? – the Type Language • We need a language for

How Types are Specified? – the Type Language • We need a language for writing types – Atomic types – Composite types – User defined types • Language expressions vs. Type expressions – Value constructors vs Type constructors • Type Polymorphism – Type variables

The Type Language • Our restricted type language: – Atomic types: Number, Boolean, Symbol,

The Type Language • Our restricted type language: – Atomic types: Number, Boolean, Symbol, Void, Empty and Procedure. – No union types. – No user-defined types.

Type Variable & Type Polymorphism What is the type of: (lambda (x) x) ?

Type Variable & Type Polymorphism What is the type of: (lambda (x) x) ? It can applied to values of any type! ( (lambda (x) x) 3) => 3 ( (lambda (x) x) #t) => #t ( (lambda (x) x) +) => <primitive: +> [Number -> Number] [Boolean -> Boolean] [[Number * Number] -> Number]

Type Variable & Type Polymorphism • We know variables that hold values. Now we

Type Variable & Type Polymorphism • We know variables that hold values. Now we have variables that holds types! • Type variables provide the necessary abstraction: we can substitute (replace) type variables by other type expressions

Type Variable & Type Polymorphism • Type of identity function is [T -> T]

Type Variable & Type Polymorphism • Type of identity function is [T -> T] • What is the type of: (lambda (f x)) [[T 1 -> T 2]*T 1 -> T 2] (lambda (f x) ( (f x) x)) [[T 1 -> T 2]]*T 1 -> T 2]

Type Variable & Type Polymorphism • Type expressions that include type variables are called

Type Variable & Type Polymorphism • Type expressions that include type variables are called polymorphic type expressions • Language expressions whose type is polymorphic are called polymorphic language expressions

Type Variable & Type Polymorphism • Unfortunately for you, checking well-typing with polymorphic types

Type Variable & Type Polymorphism • Unfortunately for you, checking well-typing with polymorphic types requires the concepts of: – Substitution – Composition of substitutions – Application of a substitution – Renaming

Type Variable & Type Polymorphism • Fortunately for you, you have already met those

Type Variable & Type Polymorphism • Fortunately for you, you have already met those concepts • More fortunately for you, we will again go over the definitions! (with type flavor)

BNF of the Type Language Type -> ’Void’ | Non-void Non-Void -> Atomic |

BNF of the Type Language Type -> ’Void’ | Non-void Non-Void -> Atomic | Composite | Type-variable Atomic -> ’Number’ | ’Boolean’ | ’Symbol’ Composite -> Procedure | Tuple Procedure -> ’[’ Tuple ’->’ Type ’]’ Tuple -> (Non-void ’*’ )* Non-void | ’Empty’ Pair -> ’Pair’ ’(’ Non-void ’, ’ Non-void ’)’ List -> ’List’ ’(’ Non-void ’)’ | ’List’ Type-variable -> A symbol

Value and Type Constructors • Value Constructor – Creates values! – Examples: 3, lambda

Value and Type Constructors • Value Constructor – Creates values! – Examples: 3, lambda • Type Constructor – Creates types! – Example: *, ->

Type Substitution Mapping s from a finite set of type variables to a finite

Type Substitution Mapping s from a finite set of type variables to a finite set to type expressions, such that s(T) does not include T. {T 1=Number, T 2=[[Number -> T 3]} {T 1=Number, T 2=[[Number -> T 3] -> T 2]} illegal

Application of Type Substitution Type expression τ, type substitution s. τ °s = replacing

Application of Type Substitution Type expression τ, type substitution s. τ °s = replacing all occurrences of type variable T in τ by s(T) [[T 1 -> T 2] ° {T 1=Number, T 2=[T 3 -> T 3]} = [[Number -> [T 3 -> T 3]]

Application of Type Substitution A type expression τ’ is an instance of typeexpression τ

Application of Type Substitution A type expression τ’ is an instance of typeexpression τ if there is a type-substitution s such that τ◦s= τ’. τ is more general than τ’ if τ’ is an instance of τ. e. g. all following are instances of [T -> T]: [Num -> Num] = [T->T]◦{T = Num} [Sym -> Sym] = [T->T]◦{T = Sym} [[Num -> Num] -> [Num -> Num]] = [T->T]◦{T = [Num->Num]} [[Num -> T 1] -> [Num -> T 1]] = [T->T]◦{T = [Num->T 1]}

Combination of Type Substitution Two type-substitution s 1, s 2 , s 1°s 2

Combination of Type Substitution Two type-substitution s 1, s 2 , s 1°s 2 is defined: 1. s 2 is applied to the type-expressions of s 1 2. A variable T for which s 1(T) is defined is removed from s 2 3. Modified s 2 is added to s 1 4. Identity bindings are removed. Relax! Examples on next slide

Examples {T 1=Number, T 2=[[Number -> T 3]} ° {T 3=Boolean, T 1=[T 2

Examples {T 1=Number, T 2=[[Number -> T 3]} ° {T 3=Boolean, T 1=[T 2 -> T 2]} = {T 1 = Number, T 2 = [[Number -> Boolean]}

Renaming Type variables can be consistently renamed, but the new variables name should be

Renaming Type variables can be consistently renamed, but the new variables name should be new. [[T 1 -> T 2]*T 1 -> T 2] [[S 1 -> T 2]*S 1 -> T 2] [[S 1 -> S 2]*S 1 -> S 2] [[T 1 -> T 2]*S 2 -> T 2] [[T 2 -> T 2]*T 2 -> T 2] [[[T 1 -> T 2]*[T 1 -> T 2]

Unifier of Type Expressions • A type-substitution s, s. t. for two type expressions

Unifier of Type Expressions • A type-substitution s, s. t. for two type expressions τ1, τ2 : τ1◦ s = τ2 ◦ s (no common type variables) • Example: – τ1 = [S*[Number->S 1]->S] – τ2 = [Pair(T 1)*[T 1 ->T 1]->T 2] – s = {S=Pair(Number), T 1=Number, S 1=Number, T 2=Pair(Number)}

Unifier of Type Expressions • Another Example: – τ1 = [S*[Number->S] – τ2 =

Unifier of Type Expressions • Another Example: – τ1 = [S*[Number->S] – τ2 = [Pair(T 1)*[T 1 ->T 1]->T 2] –s=?

Most General Unifier • There can be infinite number of unifiers. For example: –

Most General Unifier • There can be infinite number of unifiers. For example: – τ1 = [S*S->S] – τ2 = [Pair(T 1)*T 2 ->T 2] – s= • • {S=Pair(T 1), T 2=Pair(T 1)} {S=Pair(Number), T 2=Pair(Number)} {S=Pair(Boolean), T 2=Pair(Boolean)} … • Only the first one is the most general unifier (mgu)

Static Type Inference for Scheme • We start with a typing system for a

Static Type Inference for Scheme • We start with a typing system for a restricted language that includes only: – Atomic expressions with numbers, Booleans, primitive procedures, and variables – Composite expressions with quote forms, lambda forms and application forms

Terminology • Type Environment – A substitution mapping language variables to type expressions. –

Terminology • Type Environment – A substitution mapping language variables to type expressions. – Is the set of variable type assumptions – Example: Tenv = {x: Number, y: [Number –> T]} – Notation: Tenv(x) = Number – Can be extended: {x: Number, y: [Number –> T]} ◦ {z: boolean} = {x: Number, y: [Number –> T], z: boolean} {} ◦ {x 1: T 1, . . . , xn: Tn} = {x 1: T 1, . . . , xn: Tn}

Terminology • Typing statement – A true/false formula – Tenv |- e: T –

Terminology • Typing statement – A true/false formula – Tenv |- e: T – Under Tenv, the expression e has the type T • {x: Number} |- (+ x 5): Number • {x: [T 1 –> T 2], y: T 1} |- (x y): T 2

Terminology • Instantiation of Type statement – Applying substitution s to type statement TS

Terminology • Instantiation of Type statement – Applying substitution s to type statement TS – {x: [T 1 –> T 2]} |- (x e): T 2 – {x: [T 1 –> Boolean]} |- (x e): Boolean – {x: [Number –> Boolean]]} |(x e): [Number –> Boolean]

Terminology • Unifiable typing statements – Typing statements TS and TS’ are unifiable if

Terminology • Unifiable typing statements – Typing statements TS and TS’ are unifiable if there exists a type substitution s such that TS°s = TS’°s

Restricted Scheme (syntax) <scheme-exp> -> <exp> -> <atomic> | <composite> <atomic> -> <number> |

Restricted Scheme (syntax) <scheme-exp> -> <exp> -> <atomic> | <composite> <atomic> -> <number> | <boolean> | <variable> <composite> -> <special> | <form> <number> -> Numbers <boolean> -> ’#t’ | ’#f’ <variable> -> sequences of letters <special> -> <lambda> | <quote> <form> -> ’(’ <exp>+ ’)’ <lambda> -> ’(’ ’lambda’ ’(’ <variable>* ’)’ <exp>+ ’)’ <quote> -> ’(’ ’quote’ <variable> ’)’ For now: no ‘if’s, no ‘define’s and no recursive procedures

Well-Typing Rules • To infer the type of an expression (as well as whether

Well-Typing Rules • To infer the type of an expression (as well as whether or not it is well-typed), we need to define axioms and rules • To be used on sub-expressions, to derive types of the more complex expression • Only abbreviated forms are given here, see lecture notes for full description of rules.

Notes • • • Meta variables Axiom and rule independence Identifying pattern The monotonicity

Notes • • • Meta variables Axiom and rule independence Identifying pattern The monotonicity rule Exhaustive sub-expression typing We’re almost ready to see the algorithm…

Expression Trees The nesting of expressions can be viewed as a tree Sub-trees correspond

Expression Trees The nesting of expressions can be viewed as a tree Sub-trees correspond to composite expressions For lambda expressions, their body expressions reside in their children Leaves correspond to atomic ones

Expression Tree Example Tree for (+ 2 (+ 5 7)) + 2 (+ 5

Expression Tree Example Tree for (+ 2 (+ 5 7)) + 2 (+ 5 7) + 5 7

Type Derivation (inference) Algorithm Main idea: go bottom-up on the expression tree, deriving new

Type Derivation (inference) Algorithm Main idea: go bottom-up on the expression tree, deriving new type statements by using the “typestatements-pool”, rules and substitution Add the result to the type-statements-pool Declare T if you get {} |-e: T FAIL otherwise

Example Derive a typing statement for (+ 2 ( + 5 7)) (+ 2

Example Derive a typing statement for (+ 2 ( + 5 7)) (+ 2 (+ 5 7)) + 2 (+ 5 7) + 5 7

We start with the leaves: we use Number and primitives axioms. 1. 2. 3.

We start with the leaves: we use Number and primitives axioms. 1. 2. 3. 4. { { } } ||||- 5: Number 7: Number 2: Number +: [Number*Number -> Number]

Next we deal with (+ 5 7): Application axiom. For every: type environment _Tenv,

Next we deal with (+ 5 7): Application axiom. For every: type environment _Tenv, expressions _f, _e 1, . . . , _en, n >= 0 , and type expressions _S 1, . . . , _Sn, _S: Procedure with parameters (n > 0): If _Tenv |- _f: [_S 1*. . . *_Sn -> _S], _Tenv |- _e 1: _S 1, . . . , _Tenv |- _en: _Sn Then _Tenv |- (_f _e 1. . . _en): _S Application of typing rule Application to typing statements 4, 1, 2, with type substitution {_S 1=Number, _S 2=Number, _S=Number}: 5. { } |- (+ 5 7): Number

Application of typing rule Application to typing statements 4, 3, 5, with type substitution

Application of typing rule Application to typing statements 4, 3, 5, with type substitution {_S 1=Number, _S 2=Number, _S=Number}: 6. { } |- (+ 2 (+ 5 7)): Number Done

Type-Derivation Algorithm

Type-Derivation Algorithm

For Every Type Environment… • Non determinism • So: always pick a minimal type

For Every Type Environment… • Non determinism • So: always pick a minimal type environment: – Axioms user empty TE, except Variable axiom. – Procedure rule TE only with free variables – Application rule TE of existing TS

Well-typeness • e is well-typed if Type-derivation(e) does not fail. • e has a

Well-typeness • e is well-typed if Type-derivation(e) does not fail. • e has a type if it is well typed and Typederivation(e) ends with { } |- e: t

1. 2. 3. 4. 5. 6. { } |- 5: Number { } |-

1. 2. 3. 4. 5. 6. { } |- 5: Number { } |- 3: Number { } |- +: [Number*Number -> Number] {x: T} |- x: T (variable axiom) {x: T 1} |- 3: Number (monoticity) {x: T 2} |- +: [Number*Number -> Number] (monoticity) 7. {x: Number} |- (+ x 3): Number (application, unification) 8. { } |- (lambda (x) (+ x 3)): [Number -> Number] (procedure) 9. { } |- ((lambda (x) (+ x 3)) 5): Number (application)

Another Example: Fail

Another Example: Fail

1. 2. 3. 4. 5. {x 1: T 1} |- x 1: T 1

1. 2. 3. 4. 5. {x 1: T 1} |- x 1: T 1 { } |- +: [Number*Number -> Number] {x: T 2} |- x: T 2 { } |- (lambda (x 1): [T 1 -> T 1] Fail

Definitions > (define x 1) > (define y (+ x 1)) > (+ x

Definitions > (define x 1) > (define y (+ x 1)) > (+ x y) 3 What is the type of x, y, (+ x y) ?

Typing Rule Define For every definition expression (define _x _e) and type expression _S:

Typing Rule Define For every definition expression (define _x _e) and type expression _S: If { } |- _e: _S, Then { } |- _x: _S

Example Given > (define x 1) > (define y (+ x 1)) Derive a

Example Given > (define x 1) > (define y (+ x 1)) Derive a type for (+ x y)

1. { } |- 1 : Number 2. { } |- x : Number

1. { } |- 1 : Number 2. { } |- x : Number 3. { } |- + : [Number * Number] > Number 4. { } |- (+ x 1) : Number 5. { } |- y: Number 6. { } |- (+ x y): Number

Throwing in control flow (if) For every type environment _Tenv, expressions _e 1, _e

Throwing in control flow (if) For every type environment _Tenv, expressions _e 1, _e 2, _e 3, and type expressions _S 1, _S 2: If _Tenv |- _e 1: S 1 and _Tenv |- _e 2: _S 2 and _Tenv |- _e 3: _S 2 Then _Tenv |- (if _e 1 _e 2 _e 3) : _S 2

Recursions • (define f e), but e contains a free variable • We modify

Recursions • (define f e), but e contains a free variable • We modify the notion of well-typeness: – (define f e) is ok if: {f: [S 1*. . . Sn –> S]} |- e: [S 1*. . . Sn –> S]

Recursions For every: recursive-definition expression (define _f _e) and type expression _S: If {_f:

Recursions For every: recursive-definition expression (define _f _e) and type expression _S: If {_f: _S } |- _e: _S, Then { } |- (define _f _e): Void, and { } |- _f: _S

Example (define fact (λ (n) (if (= n 0) 1 (* n (fact (-

Example (define fact (λ (n) (if (= n 0) 1 (* n (fact (- n 1))))))

1. 2. 3. 4. 5. 6. {} |- =: [Num*Num -> Bool] {} |-

1. 2. 3. 4. 5. 6. {} |- =: [Num*Num -> Bool] {} |- -: [Num*Num -> Num] {} |- *: [Num*Num -> Num] {} |- 1: Num {n: T 1} |- n: T 1 {fact: T 2} |- fact: T 2 Application rule on ts 2, 4, 5 {_S 1=T 1=Num, _S 2=Num, _S=num} 7. {n: Num} |- (- n 1): num Application rule on ts 6, 7 {_S 1=Num, _S=T 3, T 2=[Num->T 3]} 8. {fact: [Num->T 3], n: Num} |(fact (- n 1)): T 3 Application rule on ts 5, 6, 8 {_S 1=Num, _S 2=Num, _S=Num, T 1=Num, T 3=Num} 9. {fact: [Num->Num], n: Num} |(* n (fact (- n 1))): Num Application rule on ts 1, 5, 4 {_S 1=Bool, _S 2=Num, _S=Bool} 10. {n: Num} |- (= n 0): Bool if rule on ts 4, 9, 10 {_S 1=Bool, _S 2=Num, _S=Bool} 11. {fact: [Num->Num], n: Num} |(if …): Num Procedure rule on ts 11 {_S 1=Num, _U 1=Num} 12. {fact: [Num->Num]} |(λ (n) (if …)): [Num -> Num] Recursive-definition to statement no. 12, with type-substitution {_S=[Number -> Number]}: 13. { } |- (define fact (λ (n) (if …))): Void 14. { } |- fact: [Num -> Num] Well typed!

Pair & List Types • Operations are primitives, so all have axioms.

Pair & List Types • Operations are primitives, so all have axioms.

Type Constraints Approach 4 Stages: I. Rename bound variables II. Assign type variable for

Type Constraints Approach 4 Stages: I. Rename bound variables II. Assign type variable for all sub-expression III. Construct type equations over these variables – Numbers, booleans, quoted symbols, primitive procedures: Construct equations using their types. – Intuitive rules for lambda and applications IV. Solve the equations

Demo by Example (λ (f g) (λ (x) (f (+ x (g 3)))))

Demo by Example (λ (f g) (λ (x) (f (+ x (g 3)))))

Stage II: Assign Type Variables Expression Variable (lambda (f g) (lambda (x) (f (+

Stage II: Assign Type Variables Expression Variable (lambda (f g) (lambda (x) (f (+ x (g 3))))) T 0 (lambda (x) (f (+ x (g 3)))) T 1 (f (+ x (g 3))) T 2 f Tf (+ x (g 3)) T 3 + T+ x Tx (g 3) T 4 g Tg 3 Tnum 3

Stage III: Construct Type Equations • Primitives: use the primitive type • λ expression:

Stage III: Construct Type Equations • Primitives: use the primitive type • λ expression: for (λ (v 1…vn) e 1…em) contruct: T(λ (v 1…vn) e 1…em)=[Tv 1*…*Tvn -> Tem] • Application: for (f e 1 … en) construct: Tf=[Te 1*…*Ten -> T(f e 1 … en)] On board

Solving the equations 1. Apply current substitution on equation 2. Check atomic types 3.

Solving the equations 1. Apply current substitution on equation 2. Check atomic types 3. If a circular substitution is created output FAIL. 4. If both sides of equation are composite and have same type constructor, split the equation into equations between corresponding components

Done! The inferred type is: [[Number -> T 2] * [Number -> Number] ->

Done! The inferred type is: [[Number -> T 2] * [Number -> Number] -> [Number -> T 2]]