CS 242 Type Types A type is a collection of computable values that share some structural property. � Examples � “Non-examples” • Integers • { 3, true, λ x.x } John Mitchell • Strings • Even integers • int → bool • { f:int → int | if x>3 then f(x) > x*(x+1) } • (int → int) → bool Distinction between types and non-types is language Reading: Chapter 6 dependent. Uses for types Type errors � Program organization and documentation � Hardware error • Separate types for separate concepts • function call x() where x is not a function – Represent concepts from problem domain • may cause jump to instruction that does not contain • Indicate intended use of declared identifiers a legal op code – Types can be checked, unlike program comments � Unintended semantics � Identify and prevent errors • int_add(3, 4.5) • Compile-time or run-time checking can prevent • not a hardware error, since bit pattern of float 4.5 meaningless computations such as 3 + true - “Bill” can be interpreted as an integer � Support optimization • just as much an error as x() above • Example: short integers require fewer bits • Access record component by known offset General definition of type error Compile-time vs run-time checking � A type error occurs when execution of program � Lisp uses run-time type checking is not faithful to the intended semantics (car x) check first to make sure x is list � ML uses compile-time type checking f(x) must have f : A → B and x : A � Do you like this definition? � Basic tradeoff • Store 4.5 in memory as a floating-point number – Location contains a particular bit pattern • Both prevent type errors • To interpret bit pattern, we need to know the type • Run-time checking slows down execution • If we pass bit pattern to integer addition function, • Compile-time checking restricts program flexibility the pattern will be interpreted as an integer pattern Lisp list: elements can have different types – Type error if the pattern was intended to represent 4.5 ML list: all elements must have same type 1
Expressiveness Relative type-safety of languages � In Lisp, we can write function like � Not safe: BCPL family, including C and C++ • Casts, pointer arithmetic (lambda (x) (cond ((less x 10) x) (T (car x)))) � Almost safe: Algol family, Pascal, Ada. Some uses will produce type error, some will not • Dangling pointers. – Allocate a pointer p to an integer, deallocate the memory � Static typing always conservative referenced by p, then later use the value pointed to by p if (big-hairy-boolean-expression) – No language with explicit deallocation of memory is fully type-safe then ((lambda (x) … ) 5) � Safe: Lisp, ML, Smalltalk, and Java else ((lambda (x) … ) 10) • Lisp, Smalltalk: dynamically typed Cannot decide at compile time if run-time error will occur • ML, Java: statically typed Type checking and type inference Motivation � Standard type checking � Types and type checking int f(int x) { return x+1; }; • Type systems have improved steadily since Algol 60 int g(int y) { return f(y+1)*2;}; • Important for modularity, compilation, reliability • Look at body of each function and use declared types of identifies to check agreement. � Type inference � Type inference • A cool algorithm int f(int x) { return x+1; }; • Widely regarded as important language innovation int g(int y) { return f(y+1)*2;}; • ML type inference gives you some idea of how many • Look at code without type information and figure out other static analysis algorithms work what types could have been declared. ML is designed to make type inference tractable. ML Type Inference Another presentation � Example � Example Graph for λ x. ((plus 2) x) - fun f(x) = 2+x; - fun f(x) = 2+x; > val it = fn : int → int > val it = fn : int → int t → int = int → int λ � How does this work? � How does this work? int (t = int) • + has two types: int*int → int, real*real → real @ Assign types to leaves • 2 : int has only one type int → int @ Propagate to internal x : t • This implies + : int*int → int nodes and generate • From context, need x: int + 2 : int constraints int → int → int • Therefore f(x:int) = 2+x has type int → int real → real → real Solve by substitution Overloaded + is unusual. Most ML symbols have unique type. In many cases, unique type may be polymorphic. 2
Application and Abstraction Types with type variables � Example : r (s = t → r) : s → t λ @ Graph for λ g. (g 2) - fun f(g) = g(2); : s : t x : s : t f x e > val it = fn : (int → t) → t s → t = (int → t) → t λ � How does this work? t (s = int → t) @ � Application � Function expression Assign types to leaves • Type is function type • f must have function type g Propagate to internal : s 2 : int domain → range domain → range nodes and generate • Domain is type of variable x • domain of f must be type constraints of argument x • Range is type of function body e • result type is range of f Solve by substitution Use of Polymorphic Function Recognizing type errors � Function � Function - fun f(g) = g(2); - fun f(g) = g(2); > val it = fn : (int → t) → t > val it = fn : (int → t) → t � Possible applications � Incorrect use - fun isEven(x) = ...; - fun add(x) = 2+x; - fun not(x) = if x then false else true; > val it = fn : int → bool > val it = fn : int → int > val it = fn : bool → bool - f(add); - f(isEven); - f(not); > val it = 4 : int > val it = true : bool Type error: cannot make bool → bool = int → t Another Type Inference Example Polymorphic Datatypes � Function Definition � Datatype with type variable ’a is syntax for “type variable a” Graph for λ〈 g,x 〉 . g(g x) - fun f(g,x) = g(g(x)); - datatype ‘a list = nil | cons of ‘a*(‘a list) > val it = fn : (t → t)*t → t > nil : ‘a list � Type Inference > cons : ‘a*(‘a list) → ‘a list s*t → v = (v → v)*v → v λ � Polymorphic function Assign types to leaves v (s = u → v) - fun length nil = 0 @ Propagate to internal | length (cons(x,rest)) = 1 + length(rest) u (s = t → u) nodes and generate g : s > length : ‘a list → int @ constraints � Type inference g : s : t x Solve by substitution • Infer separate type for each clause • Combine by making two types equal (if necessary) 3
Type inference with recursion Main Points about Type Inference � Second Clause � Compute type of expression ‘a list → int = t length(cons(x,rest)) = • Does not require type declarations for variables λ 1 + length(rest) • Find most general type by solving constraints @ � Type inference • Leads to polymorphism @ @ • Assign types to � Static type checking without type specifications @ cons leaves, including � May lead to better error detection than ordinary : ‘a*‘a list lenght rest function name + 1 type checking → ‘a list : t • Proceed as usual x • Type may indicate a programming error even if there • Add constraint that is no type error (example following slide). type of function body = type of function name We do not expect you to master this. Information from type inference Polymorphism vs Overloading � An interesting function on lists � Parametric polymorphism fun reverse (nil) = nil • Single algorithm may be given many types | reverse (x::lst) = reverse(lst); • Type variable may be replaced by any type � Most general type • f : t → t => f : int → int, f : bool → bool, ... � Overloading reverse : ‘a list → ‘b list � What does this mean? • A single symbol may refer to more than one algorithm • Each algorithm may have different type Since reversing a list does not change its type, there must be an error in the definition of • Choice of algorithm determined by type context “reverse” • Types of symbol may be arbitrarily different • + has types int*int → int, real*real → real, no others See Koenig paper on “Reading” page of CS242 site Example: swap two values Parametric Polymorphism: ML vs C++ � ML � ML polymorphic function - fun swap(x,y) = • Declaration has no type information let val z = !x in x := !y; y := z end; • Type inference: type expression with variables val swap = fn : 'a ref * 'a ref -> unit • Type inference: substitute for variables as needed � C++ function template � C++ • Declaration gives type of function arg, result template <typename T> • Place inside template to define type variables void swap(T& , T& y){ • Function application: type checker does instantiation T tmp = x; x=y; y=tmp; } ML also has module system with explicit type parameters Declarations look similar, but compiled is very differently 4
Recommend
More recommend