COS 320 March 7, 2006; Lecture 9 MinML (same definition as last lecture) Types t ::= int | bool | T1 T2 Expressions e ::= x | n | o(e e) | true | false | if e then e else e | fun f (x:T1):T2 = e | e Ops o ::= + | < | - | * Integers n Γ |- e : T “In context Γ, e is well-typed and produces a value with type T” Γ function from variables to types Γ [x:t] is a new context Γ(x) = T “look-up in the context” Goal is to have typing rules defined to prevent the following kinds of errors when executing a program, (should never run into the situation in which it is necessary to do one of the following things). 1) Apply something that isn’t a value. Eg “3 e” or (where x is not a function) “x e” 2) Never execute “if V then…” where V is not a Boolean 3) Never apply a built-in operator to the wrong kind of argument (note, I’m using in place of |- ) e1 : int e2 : int n : int e1 e2 : int e1 : int e2 : int Basic Boolean typing: true : bool false : bool e1 e2 : bool [ x : T1][f : T1 T2] e : T2 Function definition (note that on top we don’t fun f (x : T1) : T2 e : T1 T2 check x:T1) x dom() and T ( x) or x : ( x ) x : ( x ) Basic integer typing: e1 : T1 T2 e2 : T1 e1 e2 If statements (note that if e2 and e3 don’t share their types then it isn’t possible to e1 : bool e2 : T e2 : T determine at compile time the type of the if) if e1 then e2 else e3 : T Another property of our MinML rules: given a context Γ and e, either there exists a unique type T such that the judgement Γ|-e:T or e does not type check (proof by induction…take COS 441 if this is your sort of thing) type checking is syntax-directed. (this is not the case in all languages…eg in ML, the statement “let fun id x = x”). Factorial function x : int 1 : int fact : int int (x - 1) : int fact ( x 1) : int x : int 1 : int x 1 : bool 1 : int fact ( x 1) * x : 1 : int [fact : int int][ x : int] if x 1 then 1 else fact (x - 1) * x : int . fun fact (x : int) : int if x 1 then 1 else (fact (x - 1)) * x : int x : int In a nutshell: the algorithm for type checking according to the MinML rules is: Given Inputs: Context Γ and Expression e. 1) Identify the typing rule (by looking at e) 2) Recursively compute the types of the subexpressions. 3) Check constraints in rules and return the type of whole expression. Now, since Professor Walker likes to mess with us… Subtyping Add to types T “float”, add to expressions e “f”, add to ops o “+.” Define int float “ ” = “is a subtype” Type T1 is a subtype of type T2 only if all values with type T1 count as values of type T2. Every operation that handles arguments with type T2 also must handle arguments with type T1. Adding two new rules then e1 : float e2 : float e1 : T1 T1 T2 “+.” and “subsumption” e1 . e2 : float e1 : T2 Now say you define int intint…then you can say 0 : int int int int 17 : int 0 : int int this is bad, ‘nuff sed so we have to be careful 0 17 : int when selecting / subtyping rules (or really any of the rules). More extensions of MinML (moving towards ML / Fun) Add to e “(e1, …, en) | #i e” Add to T “T1 * ... * Tn” Type rules for tuples / projs e1 : T1 ... e2 : Tn e : T1 * ... * Tn and (1 i n) # i e : Ti (e1 ,..., en ) : T1 * ... * Tn k m T1 * ... * Tk T1 * ... * Tm (if you do the converse and say k can be < m, then you can say something like int * int int * int * int, and so if you try doing “#3” on something of type int * int, then it will be considered safe when it really should crash / not be allowed). Adding subtyping results in the loss of the property that every expression only has one type.