Download presentation

Presentation is loading. Please wait.

Published byMeghan Winch Modified over 2 years ago

1
Type Inference David Walker COS 320

2
Criticisms of Typed Languages Types overly constrain functions & data polymorphism makes typed constructs useful in more contexts universal polymorphism => code reuse modules & abstract types => code reuse subtyping => code reuse Types clutter programs and slow down programmer productivity type inference uninformative annotations may be omitted

3
Type Inference overview generation of type constraints from unannotated simply-typed programs Fun has subtyping and still needed some annotations There is an algorithm for complete type inference for MinML without subtyping (and of course for full ML, including parametric polymorphism) solving type constraints

4
Type Schemes A type scheme contains type variables (a, b, c) that may be filled in during type inference s ::= a | int | bool | s1 -> s2 A term scheme is a term that contains type schemes rather than proper types e ::=... | fun f (x:s1) : s2 = e

5
Example fun map (f, l) = if null (l) then nil else cons (f (hd l), map (f, tl l)))

6
Step 1: Add Type Schemes fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l), map (f, tl l))) type schemes on functions

7
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l), map (f, tl l))) for each expression, perform type inference on sub expressions, assigning them type schemes and generating constraints that must be solved

8
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l), map (f, tl l))) begin with the if expression & recursively perform type inference on its subexpressions

9
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l), map (f, tl l))) b = b’ list since argument to null must be a list

10
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l), map (f, tl l))) : d list since nil is some kind of list constraints b = b’ list

11
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l), map (f, tl l))) : d list constraints b = b’ list b = b’’ list b = b’’’ list since hd and tl are functions that take list arguments

12
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l : b’’ ), map (f, tl l : b’’’ list ))) : d list constraints b = b’ list b = b’’ list b = b’’’ list a = a

13
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l : b’’ ) : a’, map (f, tl l) : c )) : d list constraints b = b’ list b = b’’ list b = b’’’ list a = a b = b’’’ list a = b’’ -> a’

14
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l : b’’ ) : a’, map (f, tl l) : c )) : c’ list : d list constraints b = b’ list b = b’’ list b = b’’’ list a = a b = b’’’ list a = b’’ -> a’ c = c’ list a’ = c’

15
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l : b’’ ) : a’, map (f, tl l) : c )) : c’ list : d list constraints b = b’ list b = b’’ list b = b’’’ list a = a b = b’’’ list a = b’’ -> a’ c = c’ list a’ = c’ d list = c’ list

16
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l : b’’ ) : a’, map (f, tl l) : c )) : c’ list : d list constraints b = b’ list b = b’’ list b = b’’’ list a = a b = b’’’ list a = b’’ -> a’ c = c’ list a’ = c’ d list = c’ list d list = c

17
Step 2: Generate Constraints fun map (f : a, l : b) : c = if null (l) then nil else cons (f (hd l), map (f, tl l))) final constraints b = b’ list b = b’’ list b = b’’’ list a = a b = b’’’ list a = b’’ -> a’ c = c’ list a’ = c’ d list = c’ list d list = c

18
Step 3: Solve Constraints final constraints b = b’ list b = b’’ list b = b’’’ list a = a... Constraint solution provides all possible solutions to type scheme annotations on terms solution a = b’ -> c’ b = b’ list c = c’ list map (f : a -> b x : a list) : b list =...

19
Step 4: Generate types Generate types from type schemes Option 1: pick an instance of the most general type when we have completed type inference on the entire program map : (int -> int) -> int list -> int list Option 2: generate polymorphic types for program parts and continue (polymorphic) type inference map : ForAll (a,b,c) (a -> b) -> a list -> b list

20
Type Inference Details Type constraints q are sets of equations between type schemes q ::= {s11 = s12,..., sn1 = sn2} eg: {b = b’ list, a = b -> c}

21
Constraint Generation Syntax-directed constraint generation our algorithm crawls over abstract syntax of untyped expressions and generates a term scheme a set of constraints Algorithm defined as set of inference rules programming notation: tc(G, u) = (e, t, q) math notation: G |-- u => e : t, q inputs outputs

22
Constraint Generation G |-- x ==> x : G |-- 3 ==> 3 : G |-- true ==> true : G |-- false ==> false :

23
Constraint Generation G |-- x ==> x : s, { } (if G(x) = s) G |-- 3 ==> 3 : G |-- true ==> true : G |-- false ==> false :

24
Constraint Generation G |-- x ==> x : s, { } (if G(x) = s) G |-- 3 ==> 3 : int, { } G |-- true ==> true : G |-- false ==> false :

25
Constraint Generation G |-- x ==> x : s, { } (if G(x) = s) G |-- 3 ==> 3 : int, { } G |-- true ==> true : bool, { } G |-- false ==> false : bool, { }

26
Operators G |-- u1 + u2 ==>

27
Operators G |-- u1 ==> G |-- u2 ==> G |-- u1 + u2 ==>

28
Operators G |-- u1 ==> e1 G |-- u2 ==> e G |-- u1 + u2 ==>

29
Operators G |-- u1 ==> e1 G |-- u2 ==> e G |-- u1 + u2 ==> e1 + e2

30
Operators G |-- u1 ==> e1 G |-- u2 ==> e G |-- u1 + u2 ==> e1 + e2 : int

31
Operators G |-- u1 ==> e1 : t1, q1G |-- u2 ==> e2 : G |-- u1 + u2 ==> e1 + e2 : int, q1 U {t1 = int}

32
Operators G |-- u1 ==> e1 : t1, q1G |-- u2 ==> e2 : t2, q G |-- u1 + u2 ==> e1 + e2 : int, q1 U q2 U {t1 = int, t2 = int}

33
Operators G |-- u1

34
Operators G |-- u1 ==> e1 : t1, q1G |-- u2 ==> e2 : t2, q G |-- u1 e1 < e2 : bool,

35
Operators G |-- u1 ==> e1 : t1, q1G |-- u2 ==> e2 : t2, q G |-- u1 e1 < e2 : bool,

36
Operators G |-- u1 ==> e1 : t1, q1 G |-- u2 ==> e2 : t2, q G |-- u1 e1 + e2 : bool, q1 U q2 U {t1 = int, t2 = int}

37
If statements G |-- if u1 then u2 else u3 ==>

38
If statements G |-- u1 ==> e1 : t1, q1 G |-- u2 ==> e2 : t2, q2 G |-- u3 ==> e3 : t3, q G |-- if u1 then u2 else u3 ==> if e1 then e2 else e3 :

39
If statements G |-- u1 ==> e1 : t1, q1 G |-- u2 ==> e2 : t2, q2 G |-- u3 ==> e3 : t3, q G |-- if u1 then u2 else u3 ==> if e1 then e2 else e3 : a, q1 U q2 U q3 U {t1 = bool, a = t2, a = t3}

40
Function Application G |-- u1 ==> e1 : t1, q1 G |-- u2 ==> e2 : t2, q G |-- u1 u2==> e1 e2 : a, q1 U q2 U {t1 = t2 -> a}

41
Function Application G |-- u1 ==> e1 : t1, q1 G |-- u2 ==> e2 : t2, q G |-- u1 u2==> e1 e2 : a,

42
Function Declaration G, f : a -> b, x : a |-- u ==> e : t, q G |-- fun f(x) is u end ==> fun f (x : a) : b is e end : a -> b, q U {t = b}

43
Function Declaration G, f : a -> b, x : a |-- u ==> e : t, q G |-- fun f(x) = u ==> fun f (x : a) : b = e :

44
Solving Constraints A solution to a system of type constraints is a substitution S a function from type variables to type schemes, eg: S(a) = a S(b) = int S(c) = a -> a

45
Substitutions Applying a substitution S: substitute(S,int) = int substitute(S,s1 -> s2) = substitute(s1) -> substitute(s2) substitute(S,a) = s (if S(a) = s) Due to laziness, I will write S(s) instead of substitute(S, s)

46
Unification Unification: An algorithm that provides the principal solution to a set of constraints (if one exists) Unification systematically simplifies a set of constraints, yielding a substitution Starting state of unification process: (Id,q) Final state of unification process: (S, { })

47
Unification Machine We can specify unification as a rewriting system: Given (S, q), systematically pick a constraint from q and simplify it, possibly adding to the substitution Use inductive definitions to specify rewriting. Judgment form: (S,q) -> (S’,q’)

48
Unification Machine Base types & simple variables: (S,{int=int} U q) -> ???

49
Unification Machine Base types & simple variables: (S,{int=int} U q) -> (S, q)

50
Unification Machine Base types & simple variables: (S,{int=int} U q) -> (S, q) (S,{bool=bool} U q) -> ??? (S,{a=a} U q) -> ???

51
Unification Machine Base types & simple variables: (S,{int=int} U q) -> (S, q) (S,{bool=bool} U q) -> (S, q) (S,{a=a} U q) -> (S, q)

52
Unification Machine Variable definitions (a not in s) (S,{a=s} U q) -> (S[a=s], [s/a]q) (a not in s) (S,{s=a} U q) -> (S[a=s], [s/a]q)

53
Unification Machine Functions: (S,{s11 -> s12= s21 -> s22} U q) -> ???

54
Unification Machine Functions: (S,{s11 -> s12= s21 -> s22} U q) -> (S, {s11 = s21, s12 = s22} U q)

55
Occurs Check What is the solution to {a = a -> a}?

56
Occurs Check What is the solution to {a = a -> a}? There is none! The occurs check detects this situation (a not in s) (S,{s=a} U q) -> (S[a=s], [s/a]q) occurs check

57
Unification Machine Gets Stuck Recall: final states have the form (S, { }) Stuck states (S,q) are such that every equation in q has the form: int = bool s1 -> s2 = s (s not function type) a = s (s contains a) or is symmetric to one of the above Stuck states arise when constraints are unsolvable

58
Termination We want unification to terminate (to give us a type reconstruction algorithm) In other words, we want to show that there is no infinite sequence of states (S1,q1) -> (S2,q2) ->...

59
Termination We associate an ordering with constraints q < q’ if and only if q contains fewer variables than q’ q contains the same number of variables as q’ but fewer type constructors (ie: fewer occurrences of int, bool, or “->”) This is a lexicographic ordering we can prove (by contradiction) that there is no infinite decreasing sequence of constraints

60
Termination Lemma: Every step reduces the size of q Proof: Examine each case of the definition of the reduction relation & show that our metric goes down (S,{int=int} U q) -> (S, q) (S,{bool=bool} U q) -> (S, q) (S,{a=a} U q) -> (S, q) (S,{s11 -> s12= s21 -> s22} U q) -> (S, {s11 = s21, s12 = s22} U q) (a not in FV(s)) (S,{a=s} U q) -> (S[a=s], [s/a]q)

61
Properties of Solutions given any set of constraints q, our unification machine reduces (Id, q) to (S, { }) such that S(q) is a set of true equations (eg, int = int, bool -> a = bool -> a, etc) S is a principal solution to the constraints. it generates more general types than any other substitution T: ie: a -> a is more general than int -> int ie: T replaces more type variables with more specific types

62
Summary: Type Inference Type inference algorithm. Given a context G, and untyped term u: Find e, t, q such that G |- u ==> e : t, q Find principal solution S of q via unification if no solution exists, there is no way to type check the term Apply S to e, ie our solution is S(e) S(e) contains schematic type variables a,b,c, etc that may be instantiated with any type Since S is principal, S(e) characterizes all possible typings of e

63
Compare with Subtyping Algorithm Simple type inference algorithm. Given a context G (mapping variables to type schemes), and untyped term u: Find e, t, q such that G |- u ==> e : t, q Type equations collected on the side Subtyping algorithm given a context G (mapping variables to full types) Find t such that G |-- e : t Subtyping equations solved when they are generated Lots of current research on type inference that combines subtyping and polymorphic type reconstruction for advanced type systems

Similar presentations

© 2017 SlidePlayer.com Inc.

All rights reserved.

Ads by Google