Type Checking and Type Inference Principles of Programming Languages CSE 307 1 Types in Programming Languages 2 Static Type Checking 3 Polymorphic Type Inference Version: 1.8 17:20:56 2014/08/25 Compiled at 18:31 on 2014/12/01 Programming Languages Type Checking and Inference CSE 307 1 / 41
Use of datatype information The set of possible values denoted by a name or kept in a cell in store is denoted by a data type. Common data types include integers, floating point or real numbers, Booleans, and structured data. The type information is used for many purposes: Data representation: Type determines how data is represented (e.g. fixed precision integers; floating point for reals) Operation selection: Type information is used to select which among a set of overloaded operators is applied. (e.g. in x+y, a.f(b)). Compile-time error detection: Type information is used to check for operations on inappropriate data. Programming Languages Type Checking and Inference CSE 307 2 / 41
Languages and Datatypes (1) Dynamically-typed languages: The datatype information is known and tracked only at run-time. So, data representation, operation selection, and error detection can all be performed only at run-time. Languages such as Scheme, Prolog, Python, and Javascript are all dynamically typed. Statically-typed languages: The datatype information is tracked and checked at compile-time, before a program s execution. Data representation is determined at compile time. Much of operation selection and error detection can be performed at compile-time as well. Languages such as SML, C, and Pascal are statically typed. Java is considered statically-typed as well even though operation selection and some of error detection is performed at run-time. Programming Languages Type Checking and Inference CSE 307 3 / 41
Languages and Datatypes (2) Strongly-typed languages: The datatype information is used to ensure error-free operations. Languages such as SML, Java, Scheme, Prolog, Python, and Ruby are all strongly typed. Languages such as C, C++, and Perl are not strongly typed (aka weakly typed). Common confusion: static typing vs. strong typing. Statically typed Dynamically typed Strongly typed SML, Java Scheme, Prolog, Python Weakly typed C, C++ Perl Static/dynamic only refers to when type information is known and tracked. Strong/weak refers to whether type information is always tracked and whether it is used for operation selection/error detection. Programming Languages Type Checking and Inference CSE 307 4 / 41
Why is C weakly typed? Use of type casts on pointers (e.g. a pointer to void can be cast to be a pointer to int). Use of unions: overlapping memory areas used for different types of values. Lack of memory safety (array bounds, dangling references to automatic variables). Programming Languages Type Checking and Inference CSE 307 5 / 41
Static Type Checking A procedure that, without running the program, determines the types of expressions and checks for improper operations. We generally use this terminology for checking datatypes without considering the control flow of the program (aka flow-insensitive). Type-checking techniques are used for more complex types, e.g. non-null references, which may use control flow information (e.g. type of a variable at a specific statement in the program). Static type checking can be (and is often) specified using inference rules. Programming Languages Type Checking and Inference CSE 307 6 / 41
Type Checking Given an expression e and a type t, is the expression well-typed w.r.t. t? e.g. is x+y:int well typed?... depends on the types of x and y Type environment Γ: a function that associates a type with each name in the program. e.g. {x int, y int}. Type judgement Γ e : t Under type environment Γ the expression e has type t. Type inference: given an expression e, is there a type t such that e is well-typed w.r.t. t? Programming Languages Type Checking and Inference CSE 307 7 / 41
Type Expressions We can construct expressions over types analogous to how we construct arithmetic and boolean expressions over numeric and boolean constants and variables. Type expressions can be: Type names (e.g. int, bool, float) t 1 t 2 where t 1, t 2 are type exprs. t 1 t 2 where t 1, t 2 are type exprs. list of t where t is a type expr. ref t where t is a type expr.... Type variables (e.g. α, α, β,...) Programming Languages Type Checking and Inference CSE 307 8 / 41
Example Expression Language We will use a small language of expressions for formally defining a type system and the corresponding type checking and inference procedures. As usual, we will start with a trivial language and add language constructs as we proceed. Ultimately, this language will look (i.e. be syntactically) and behave (i.e. be semantically) similar to OCAML. Programming Languages Type Checking and Inference CSE 307 9 / 41
Constants Boolean Constants: true, false, represented in abstract syntax as True and False, resp. Integer Constants: usual, represented in abstract syntax as Int(i) Floating Point Constants: usual, represented in abstract syntax as Float(x) Unit Constant: written in concrete syntax as () and represented in abstract syntax as Unit. Programming Languages Type Checking and Inference CSE 307 10 / 41
Type Rules Constants Int Float Bool t Bool f Unit Γ Int(i) : int Γ Float(x) : float Γ True : bool Γ False : bool Γ Unit : unit Each type judgement of the form Γ e : t associates a type t with expression e in type environment Γ. The inference of types for constants, as specified above, is trivial. Unsurprising fact: the type environment is not used to infer types of constants. Programming Languages Type Checking and Inference CSE 307 11 / 41
Boolean Operators And(e 1, e 2 ), Or(e 1, e 2 ), Not(e 1 ) where e 1 and e 2 are expressions. Note that concrete syntax may use an infix notation for these operators. If(e 1, e 2, e 3 ), where e 1, e 2 and e 3 are expressions. In concrete syntax, these expressions may be written as: if e 1 then e 2 else e 3 Programming Languages Type Checking and Inference CSE 307 12 / 41
Type Rules Boolean Operators And Or Not If Γ e 1 : bool Γ e 2 : bool Γ And(e 1, e 2 ) : bool Γ e 1 : bool Γ e 2 : bool Γ Or(e 1, e 2 ) : bool Γ e 1 : bool Γ Not(e 1 ) : bool Γ e 1 : bool Γ e 2 : t Γ e 3 : t Γ If(e 1, e 2, e 3 ) : t Note the use of t in the If rule: The condition in if must be a bool The then- and else- expressions must be of same (but arbitrary) type t. The whole expression will then have type t. Programming Languages Type Checking and Inference CSE 307 13 / 41
Arithmetic Operators Add(e 1, e 2 ), Sub(e 1, e 2 ),... where e 1 and e 2 are expressions. Comparison operations such as Equal(e 1, e 2 ), Less(e 1, e 2 ),... where e 1 and e 2 are expressions. Note that concrete syntax may use an infix notation for these operators. Programming Languages Type Checking and Inference CSE 307 14 / 41
Type Rules Arithmetic Operators Add 1 Add 2 Add 3 Add 4 Γ e 1 : int Γ e 2 : int Γ Add(e 1, e 2 ) : int Γ e 1 : int Γ e 2 : float Γ Add(e 1, e 2 ) : float Γ e 1 : float Γ e 2 : int Γ Add(e 1, e 2 ) : float Γ e 1 : float Γ e 2 : float Γ Add(e 1, e 2 ) : float The type rules explicitly list the cases when the built-in operators are overloaded. Type rules for other arithmetic operators are similar. Programming Languages Type Checking and Inference CSE 307 15 / 41
Let Expressions We now add the ability to give names to expressions and use them elsewhere, as in: let x = 2 in x+3 Concrete syntax: let v = e 1 in e 2 Abstract syntax: let(v, e 1, e 2 ), where v is an identifier, and e 1 and e 2 are expressions. Programming Languages Type Checking and Inference CSE 307 16 / 41
Type Rules Let Expressions Var Let (x t) Γ Γ Id(x) : t Γ e 1 : t 1 (x t 1 ) Γ e 2 : t Γ Let(x, e 1, e 2 ) : t The Var rule uses the type environment to determine the type of an identifier. In the Let rule, the type of the entire expression is the same as the type of the inner expression e 2 since e 2 may have x free, its type environment needs to specify the type of x and that type is same as the type of e 1. Programming Languages Type Checking and Inference CSE 307 17 / 41
Functions Following the lambda calculus: Abstraction for defining new functions. Concrete syntax: fun x -> e Abstract syntax: fun(x, e), where x is an identifier and e is an expression. Application for calling functions. Concrete syntax: (e 1 e 2 ) Abstract syntax: apply(e 1, e 2 ), where e 1 and e 2 are expressions. Programming Languages Type Checking and Inference CSE 307 18 / 41
Type Rules Functions Fun App (x t 1 ) Γ e : t 2 Γ Fun(x, e) : t 1 t 2 Γ e 1 : t 2 t Γ e 2 : t 2 Γ Apply(e 1, e 2 ) : t The Fun rule augments the environment with the formal parameter s type; and uses this environment to determine the type of e. According to the App rule, the first expression must be a function (of type t 1 t 2 ) and the second expression s type must match that of the function s parameter. Programming Languages Type Checking and Inference CSE 307 19 / 41
Type Rules Functions(2) Fun App (x t 1 ) Γ e : t 2 Γ Fun(x, e) : t 1 t 2 Γ e 1 : t 2 t Γ e 2 : t 2 Γ Apply(e 1, e 2 ) : t In Fun(x, e), the type of x is not specified, so t 1 can be any type Programming Languages Type Checking and Inference CSE 307 20 / 41
Type Rules Functions(2) Fun App (x t 1 ) Γ e : t 2 Γ Fun(x, e) : t 1 t 2 Γ e 1 : t 2 t Γ e 2 : t 2 Γ Apply(e 1, e 2 ) : t In Fun(x, e), the type of x is not specified, so t 1 can be any type... as long as, for that t 1, e has a valid type. Programming Languages Type Checking and Inference CSE 307 20 / 41
Type Rules Functions(2) Fun App (x t 1 ) Γ e : t 2 Γ Fun(x, e) : t 1 t 2 Γ e 1 : t 2 t Γ e 2 : t 2 Γ Apply(e 1, e 2 ) : t In Fun(x, e), the type of x is not specified, so t 1 can be any type... as long as, for that t 1, e has a valid type. As a consequence, Fun(x, e) may not have a unique type! Programming Languages Type Checking and Inference CSE 307 20 / 41
Type Rules Functions(2) Fun App (x t 1 ) Γ e : t 2 Γ Fun(x, e) : t 1 t 2 Γ e 1 : t 2 t Γ e 2 : t 2 Γ Apply(e 1, e 2 ) : t In Fun(x, e), the type of x is not specified, so t 1 can be any type... as long as, for that t 1, e has a valid type. As a consequence, Fun(x, e) may not have a unique type! E.g., Fun(x, Id(x)) has type int int, float float, bool bool, int int int int,... Programming Languages Type Checking and Inference CSE 307 20 / 41
Type Rules Functions(2) Fun App (x t 1 ) Γ e : t 2 Γ Fun(x, e) : t 1 t 2 Γ e 1 : t 2 t Γ e 2 : t 2 Γ Apply(e 1, e 2 ) : t In Fun(x, e), the type of x is not specified, so t 1 can be any type... as long as, for that t 1, e has a valid type. As a consequence, Fun(x, e) may not have a unique type! E.g., Fun(x, Id(x)) has type int int, float float, bool bool, int int int int,... In ML, we have variables ranging over types (aka type variables). This lets us define the most general type of an expression, called its principal type. Programming Languages Type Checking and Inference CSE 307 20 / 41
Pairs As in C, pair datatypes are added with: Pair constructor (concrete: (e 1, e 2 ); abstract: Pair(e 1, e 2 )). Fst and Snd access operators (concrete: e.1, and e.2, respectively; abstract: Fst(e) and Snd(e)). Programming Languages Type Checking and Inference CSE 307 21 / 41
Type Rules Datatypes: Pairs Pair Fst Snd Γ e 1 : t 1 Γ e 2 : t 2 Γ Pair(e 1, e 2 ) : t 1 t 2 Γ e : t 1 t 2 Γ Fst(e) : t 1 Γ e : t 1 t 2 Γ Snd(e) : t 2 The Pair rule judges the type of the constructed pair using the types of its components. The Fst and Snd rules apply only when the operand is of a pair type; the rules then specify which component of the pair type to extract. Programming Languages Type Checking and Inference CSE 307 22 / 41
Lists Similar to pairs, lists can be added with: Cons and Nil constructors (concrete: e 1 ::e 2, and [], respectively; abstract: Cons(e 1, e 2 ), and Nil). Hd and Tl access operators (concrete: hd(e), and tl(e), respectively; abstract: Hd(e) and Tl(e)). isnil operator to test whether a list is nil or not. Programming Languages Type Checking and Inference CSE 307 23 / 41
Type Rules Lists Cons Nil Hd Tl IsNil Γ e 1 : t Γ e 2 : list of t Γ Cons(e 1, e 2 ) : list of t Γ Nil : list of t Γ e : list of t Γ Hd(e) : t Γ e : list of t Γ Tl(e) : list of t Γ e : list of t Γ IsNil(e) : bool Programming Languages Type Checking and Inference CSE 307 24 / 41
References Finally, we add OCAML-style references for writing programs with side effects. Ref(e) to create new references (initialized to the value of e) Deref(e) to dereference an existing reference (concrete syntax:!e) Assign(e 1, e 2 ) to assign the value of one expression (e 2 ) to the location supplied by another expression (e 1 ). Concrete syntax: e 1 := e 2 Programming Languages Type Checking and Inference CSE 307 25 / 41
Type Rules References Ref Deref Assign Γ e 1 : t 1 Γ Ref(e 1 ) : ref t 1 Γ e 1 : ref t 1 Γ Deref(e 1 ) : t 1 Γ e 1 : ref t 1 Γ e 2 : t 1 Γ Assign(e 1, e 2 ) : unit The Ref rule judges the type of the constructed cell using the type of the stored value. The Deref rule does the converse: determines the type of a value in a cell based on the type of its reference. The Assign requires the l.h.s. to be a reference type, and r.h.s. to be a value of the same type. Programming Languages Type Checking and Inference CSE 307 26 / 41
Type Inference Infer the type of an expression given the types of the subexpressions. Consider the expression fst(1,2): Int(1) Int(2) Pair Fst Programming Languages Type Checking and Inference CSE 307 27 / 41
Type Inference Infer the type of an expression given the types of the subexpressions. Consider the expression fst(1,2): Int(1) :int Int(2) :int Pair Fst Type of Int(1) and Int(2) are int (from rules for constants) Programming Languages Type Checking and Inference CSE 307 27 / 41
Type Inference Infer the type of an expression given the types of the subexpressions. Consider the expression fst(1,2): Int(1) :int Int(2) :int Pair :int * int Fst Type of Int(1) and Int(2) are int (from rules for constants) Type of Pair(e 1, e 2 ) is t 1 t 2 where t i is the type of e i (from Pair rule) Programming Languages Type Checking and Inference CSE 307 27 / 41
Type Inference Infer the type of an expression given the types of the subexpressions. Consider the expression fst(1,2): Int(1) :int Int(2) :int Pair :int * int Fst :int Type of Int(1) and Int(2) are int (from rules for constants) Type of Pair(e 1, e 2 ) is t 1 t 2 where t i is the type of e i (from Pair rule) Type of Fst(e) is t 1 if e is of type t 1 t 2 (from Fst rule) Programming Languages Type Checking and Inference CSE 307 27 / 41
Type Reconstruction Introduction Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider the expression fst(x,y): Id(x) Id(y) Pair Fst Programming Languages Type Checking and Inference CSE 307 28 / 41
Type Reconstruction Introduction Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider the expression fst(x,y): Id(x) : α Id(y) : β Pair Fst Types of x and y are assumed to be α and β. (i.e., some unknown type, but not necessarily the same). Programming Languages Type Checking and Inference CSE 307 28 / 41
Type Reconstruction Introduction Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider the expression fst(x,y): Id(x) : α Id(y) : β Pair : α β Fst Types of x and y are assumed to be α and β. (i.e., some unknown type, but not necessarily the same). Type of Pair(e 1, e 2 ) is t 1 t 2 where t i is the type of e i (from Pair rule) Programming Languages Type Checking and Inference CSE 307 28 / 41
Type Reconstruction Introduction Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider the expression fst(x,y): Id(x) : α Id(y) : β Pair : α β Fst : α Types of x and y are assumed to be α and β. (i.e., some unknown type, but not necessarily the same). Type of Pair(e 1, e 2 ) is t 1 t 2 where t i is the type of e i (from Pair rule) Type of Fst(e) is t 1 if e is of type t 1 t 2 (from Fst rule) Programming Languages Type Checking and Inference CSE 307 28 / 41
Type Reconstruction Example 2 Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider fun x -> fun y -> x: Id(x) y Fun x Fun Programming Languages Type Checking and Inference CSE 307 29 / 41
Type Reconstruction Example 2 Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider fun x -> fun y -> x: Id(x) y Fun x : α Fun Types of x and y are assumed to be α and β. (i.e., some unknown type, but not necessarily the same). Programming Languages Type Checking and Inference CSE 307 29 / 41
Type Reconstruction Example 2 Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider fun x -> fun y -> x: Id(x) y : β Fun x : α Fun Types of x and y are assumed to be α and β. (i.e., some unknown type, but not necessarily the same). Programming Languages Type Checking and Inference CSE 307 29 / 41
Type Reconstruction Example 2 Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider fun x -> fun y -> x: Id(x) : α y : β Fun x : α Fun Types of x and y are assumed to be α and β. (i.e., some unknown type, but not necessarily the same). Type of innermost x is same as its assumption (Id rule). Programming Languages Type Checking and Inference CSE 307 29 / 41
Type Reconstruction Example 2 Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider fun x -> fun y -> x: Id(x) : α y : β Fun : β α x : α Fun Types of x and y are assumed to be α and β. (i.e., some unknown type, but not necessarily the same). Type of innermost x is same as its assumption (Id rule). Type of (fun y ->e) is t 1 t 2 if y is of type t 2 (from Fun rule) Programming Languages Type Checking and Inference CSE 307 29 / 41
Type Reconstruction Example 2 Can we infer the types of the subexpressions (or at least, some constraints on their types) assuming the full expression is well-typed? Consider fun x -> fun y -> x: Id(x) : α y : β Fun : β α x : α Fun : α β α Types of x and y are assumed to be α and β. (i.e., some unknown type, but not necessarily the same). Type of innermost x is same as its assumption (Id rule). Type of (fun y ->e) is t 1 t 2 if y is of type t 2 (from Fun rule) Type of (fun x ->e) is t 1 t 2 if x is of type t 2 (from Fun rule) Programming Languages Type Checking and Inference CSE 307 29 / 41
Type Reconstruction Example 3 Consider fun x -> if fst(x) then 1 else snd(x) Since the entire expression is of the form fun x -> e, its type is α β, where x : α and e : β. Let s determine the type of e under the environment {x α}. Since e is an if expression, we have the following: 1 fst(x) : bool 2 1: β 3 snd(x): β From 1: β, we get β = int. From x:α and fst(x):bool, and from the rule Fst, we get α = bool γ. From x:α and snd(x):int, and from the rule Snd, we get, α = δ int. From the last two steps, we get α = bool int and hence the original expressions type is: bool int int Programming Languages Type Checking and Inference CSE 307 30 / 41
Type Unification Motivation In the previous example, we initially assigned types denoted by type variables to certain identifiers. As type inference proceeded, we discovered constraints on those type variables, e.g. α = bool γ. The constraints are all equality constraints, hence if α 1 = α 2 and α 2 = α 3 then α 1 = α 3. From bool γ = δ int, we get γ = int and δ = bool. More formally, the constraints are solved using unification, defined next. Programming Languages Type Checking and Inference CSE 307 31 / 41
Type Unification Two type expressions t 1, t 2 are said to unify iff there is some substitution θ to the type variables in t 1 and t 2 such that t 1 θ = t 2 θ. Examples: A type variable α unifies with any type expression t that does not contain α. α and list of β unify, setting α = list of β. list of α and list of β unify, setting α = β. int and list of β do not unify. α 1 α 2 and list of β do not unify. α and list of α do not unify. Type unification is the core of Hindley-Milner type inference. Programming Languages Type Checking and Inference CSE 307 32 / 41
Polymorphic Types The type rules can be used to find out the constraints on Γ and t such that Γ e : t is derivable from the empty type judgement. We will illustrate the use of these rules informally: Find the type of fun x -> x Programming Languages Type Checking and Inference CSE 307 33 / 41
Polymorphic Types The type rules can be used to find out the constraints on Γ and t such that Γ e : t is derivable from the empty type judgement. We will illustrate the use of these rules informally: Find the type of fun x -> x Since it is a function definition, we represent the type of its formal parameter to be some type variable, say α. Programming Languages Type Checking and Inference CSE 307 33 / 41
Polymorphic Types The type rules can be used to find out the constraints on Γ and t such that Γ e : t is derivable from the empty type judgement. We will illustrate the use of these rules informally: Find the type of fun x -> x Since it is a function definition, we represent the type of its formal parameter to be some type variable, say α. We evaluate the type of the function s body assuming x is of type α. Programming Languages Type Checking and Inference CSE 307 33 / 41
Polymorphic Types The type rules can be used to find out the constraints on Γ and t such that Γ e : t is derivable from the empty type judgement. We will illustrate the use of these rules informally: Find the type of fun x -> x Since it is a function definition, we represent the type of its formal parameter to be some type variable, say α. We evaluate the type of the function s body assuming x is of type α. The type of its body is then determined to be α as well. Programming Languages Type Checking and Inference CSE 307 33 / 41
Polymorphic Types The type rules can be used to find out the constraints on Γ and t such that Γ e : t is derivable from the empty type judgement. We will illustrate the use of these rules informally: Find the type of fun x -> x Since it is a function definition, we represent the type of its formal parameter to be some type variable, say α. We evaluate the type of the function s body assuming x is of type α. The type of its body is then determined to be α as well. Som the function s type is α α. Programming Languages Type Checking and Inference CSE 307 33 / 41
Polymorphic Types (contd.) A function is said to be polymorphic if it has more than one type. Since fun x -> x is of type α α for any type α, the function is polymorphic. This form of polymorphism is called parametric polymorphism: f is polymorphic w.r.t. type parameter α. The type parameter for fun x -> x is implicit, and so this is also called implicit parametric polymorphism. Consider the following OCAML definition of a tree data structure: type a tree = Empty Node of a * a tree * a tree;; This defines trees for different node types, and hence is polymorphic. Since the node types is given as a parameter to the datatype definition, this is called implicit parametric polymorphism. Programming Languages Type Checking and Inference CSE 307 34 / 41
Unification and parametric polymorphism Consider fun x -> if (fst(x)) then 1 else (x,1) If the type of the expression is α β, we get: 1 1 : β, which means β = int, and 2 (x,1) : β, which means β = α int. int and α int do not unify! Hence there is no type for the expression. The expression is not well-typed. Programming Languages Type Checking and Inference CSE 307 35 / 41
Omega Consider fun x -> (x x) This is the first part of the ω-combinator introduced in the lambda calculus. If the type of the expression is α β, we get 1 x : α, and 2 (x x) : β Rule App says that if (e 1 e 2 ) : β then e 1 : γ β and e 2 : γ. Hence we also have the following constraints: 1 x : γ β 2 x : γ γ and γ β do not unify! Hence ω is not well-typed. By a similar argument, we can show that the Y-combinator is also not well-typed. Programming Languages Type Checking and Inference CSE 307 36 / 41
ML s Type Inference ML s type inference proceeds very similar to our definition of types, with two main changes. 1 ML s let is polymorphic: every use of a let-defined identifier may have a different, incompatible type. Our rules have (implicitly) demanded that all uses of an identifier have the same consistent set of types. 2 ML has user-defined types and uses pattern matching in function definitions. Type checking for these can also be formalized as inference rules, but following them strictly becomes tedious, so we ll explain these only with examples. Programming Languages Type Checking and Inference CSE 307 37 / 41
ML s Type Inference Example 1 Find the type of g defined as let g y = match y with (x::xs) -> x 1 We know g is a function so has type α β. Programming Languages Type Checking and Inference CSE 307 38 / 41
ML s Type Inference Example 1 Find the type of g defined as let g y = match y with (x::xs) -> x 1 We know g is a function so has type α β. 2 Hence y is of type α. Programming Languages Type Checking and Inference CSE 307 38 / 41
ML s Type Inference Example 1 Find the type of g defined as let g y = match y with (x::xs) -> x 1 We know g is a function so has type α β. 2 Hence y is of type α. 3 For match, the pattern (x::xs) must have type α, same as y. Programming Languages Type Checking and Inference CSE 307 38 / 41
ML s Type Inference Example 1 Find the type of g defined as let g y = match y with (x::xs) -> x 1 We know g is a function so has type α β. 2 Hence y is of type α. 3 For match, the pattern (x::xs) must have type α, same as y. 4 From the definition of :: we now infer that α = γ list, x is of type γ and xs is of type γ list. Programming Languages Type Checking and Inference CSE 307 38 / 41
ML s Type Inference Example 1 Find the type of g defined as let g y = match y with (x::xs) -> x 1 We know g is a function so has type α β. 2 Hence y is of type α. 3 For match, the pattern (x::xs) must have type α, same as y. 4 From the definition of :: we now infer that α = γ list, x is of type γ and xs is of type γ list. 5 The return type of g must be same as the type of x; hence from (1) and (3), we know β = γ. Programming Languages Type Checking and Inference CSE 307 38 / 41
ML s Type Inference Example 1 Find the type of g defined as let g y = match y with (x::xs) -> x 1 We know g is a function so has type α β. 2 Hence y is of type α. 3 For match, the pattern (x::xs) must have type α, same as y. 4 From the definition of :: we now infer that α = γ list, x is of type γ and xs is of type γ list. 5 The return type of g must be same as the type of x; hence from (1) and (3), we know β = γ. 6 Hence g has type γ list γ. Programming Languages Type Checking and Inference CSE 307 38 / 41
ML s Type Inference Example 2 Find the type of len defined by let rec len y = match y with [ ] > 0 (x::xs) > 1 + (len xs) 1 We know len is a function so has type α β. Programming Languages Type Checking and Inference CSE 307 39 / 41
ML s Type Inference Example 2 Find the type of len defined by let rec len y = match y with [ ] > 0 (x::xs) > 1 + (len xs) 1 We know len is a function so has type α β. 2 The expression [] (l.h.s. pattern of first match case) must have type α; from the definition of [] we now infer that α = γ list. Programming Languages Type Checking and Inference CSE 307 39 / 41
ML s Type Inference Example 2 Find the type of len defined by let rec len y = match y with [ ] > 0 (x::xs) > 1 + (len xs) 1 We know len is a function so has type α β. 2 The expression [] (l.h.s. pattern of first match case) must have type α; from the definition of [] we now infer that α = γ list. 3 The return type of len must be same as the type of 0; hence from (1), we know β = int. Programming Languages Type Checking and Inference CSE 307 39 / 41
ML s Type Inference Example 2 Find the type of len defined by let rec len y = match y with [ ] > 0 (x::xs) > 1 + (len xs) 1 We know len is a function so has type α β. 2 The expression [] (l.h.s. pattern of first match case) must have type α; from the definition of [] we now infer that α = γ list. 3 The return type of len must be same as the type of 0; hence from (1), we know β = int. 4 From the second match case, if α = γ list then x must be of type γ and xs must be of type γ list. Programming Languages Type Checking and Inference CSE 307 39 / 41
ML s Type Inference Example 2 Find the type of len defined by let rec len y = match y with [ ] > 0 (x::xs) > 1 + (len xs) 1 We know len is a function so has type α β. 2 The expression [] (l.h.s. pattern of first match case) must have type α; from the definition of [] we now infer that α = γ list. 3 The return type of len must be same as the type of 0; hence from (1), we know β = int. 4 From the second match case, if α = γ list then x must be of type γ and xs must be of type γ list. 5 From (3), we know the rhs of second eqn must be of type int. Programming Languages Type Checking and Inference CSE 307 39 / 41
ML s Type Inference Example 2 Find the type of len defined by let rec len y = match y with [ ] > 0 (x::xs) > 1 + (len xs) 1 We know len is a function so has type α β. 2 The expression [] (l.h.s. pattern of first match case) must have type α; from the definition of [] we now infer that α = γ list. 3 The return type of len must be same as the type of 0; hence from (1), we know β = int. 4 From the second match case, if α = γ list then x must be of type γ and xs must be of type γ list. 5 From (3), we know the rhs of second eqn must be of type int. 6 len is of type γ list int. Since xs is of type γ list, len xs is int. Since 1 is of type int, 1 + len xs is of type int as required by (5). Hence len is well typed and has type γ list int. Programming Languages Type Checking and Inference CSE 307 39 / 41
ML s Type Inference (Example 2-a) Find the type of len2a defined by let rec len2a y = match y with [ ] > 0 (x::xs) > 1.0 + (len2a xs) 1 5. The first 5 steps are the same as in the previous example. 6. We know that len2a is of type γ list int. Since xs is of type γ list, len2a xs is of type int. Since 1.0 is of type float, 1 + len2a xs is not well typed. Hence len2a is not well typed. Programming Languages Type Checking and Inference CSE 307 40 / 41
ML s Type Inference (Example 2-b) Find the type of len2a defined by let rec len2b y = match y with [ ] > 0 (x::xs) > 1 + (len2b x) 1 5. The first 5 steps are the same as in the previous example. 6. We know that len2b is of type γ list int. Since x is of type γ for len2b x to be well typed, γ = γ list. Since there is no type γ such that γ = γ list (see Type Unification), len2b x is not well typed. Hence len2b is not well typed. Programming Languages Type Checking and Inference CSE 307 41 / 41