Hindley-Milner Type Checking Automatic Type Inference What can be - - PowerPoint PPT Presentation

hindley milner type checking automatic type inference
SMART_READER_LITE
LIVE PREVIEW

Hindley-Milner Type Checking Automatic Type Inference What can be - - PowerPoint PPT Presentation

CSE340 Principles of Programming Languages Hindley-Milner Type Checking Automatic Type Inference What can be inferred about type of f or x from this definition? f(x) = x Automatic Type Inference f(x) = x f is a function that takes a single


slide-1
SLIDE 1

CSE340 Principles of Programming Languages

Hindley-Milner Type Checking

slide-2
SLIDE 2

f(x) = x

Automatic Type Inference

What can be inferred about type of f or x from this definition?

slide-3
SLIDE 3

f(x) = x

Automatic Type Inference

f is a function that takes a single

  • argument. So the type of f can be

described as: T1(*)(T2)

slide-4
SLIDE 4

f(x) = x

Automatic Type Inference

The return value of f is equal to its input, so their types must match: T1 = T2

slide-5
SLIDE 5

f(x) = x

Automatic Type Inference

So f is a function that takes one argument and its return type is the same as its argument’s type. Therefore type of f is: T1(*)(T1)

slide-6
SLIDE 6

f(x) = x

Automatic Type Inference

And we don’t know anything about the type of x So f is a function that takes one argument and its return type is the same as its argument’s type. Therefore type of f is: T1(*)(T1)

slide-7
SLIDE 7

g(x) = x + 1

Automatic Type Inference

How about function g?

slide-8
SLIDE 8

g(x) = x + 1

Automatic Type Inference

What can be inferred from this term?

slide-9
SLIDE 9

g(x) = x + 1

Automatic Type Inference

x is used in an arithmetic expression involving the integer constant 1. So x must be of integer type

slide-10
SLIDE 10

g(x) = x + 1

Automatic Type Inference

So the type of function g should be further restricted to: int(*)(int)

slide-11
SLIDE 11

To perform Hindley-Milner type checking:

  • Start by generating the abstract syntax tree of the function
  • Assume unknown types for arguments: T1, T2, …
  • Examine the tree nodes and apply type constraints to further restrict the

types

  • The type constraints that can be applied depend on the programming

language used. In the following examples we use simple rules similar to those in functional languages like OCaml

slide-12
SLIDE 12

Examples

slide-13
SLIDE 13

f(a,b,c,d) = if b = 1 then if a[1](0) then c(1) else c(d) else if a[b](0) then c(b) else f(a, b - 1, c, d)

Example #1

slide-14
SLIDE 14

f(a,b,c,d) = if b = 1 then if a[1](0) then c(1) else c(d) else if a[b](0) then c(b) else f(a, b - 1, c, d)

Example #1

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

slide-15
SLIDE 15

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

slide-16
SLIDE 16

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

Condition Then Else

slide-17
SLIDE 17

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

Condition Then Else

slide-18
SLIDE 18

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

Condition Then Else

slide-19
SLIDE 19

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

The function Parameters in order from left to right

slide-20
SLIDE 20

f T1(*)(T2,T3,T4,T5) a T2 b T3 c T4 d T5

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

slide-21
SLIDE 21

Top-Down order

slide-22
SLIDE 22

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

f T1(*)(T2,T3,T4,T5) a T2 b T3 c T4 d T5

T1

The return type of the function should be the same as the type of the if node

slide-23
SLIDE 23

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

f T1(*)(T2,T3,T4,T5) a T2 b T3 c T4 d T5

T1 bool

The condition should be of type boolean

slide-24
SLIDE 24

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

f T1(*)(T2,T3,T4,T5) a T2 b T3 c T4 d T5

T1 bool T1

The then node should be of the same type as the if node

slide-25
SLIDE 25

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

f T1(*)(T2,T3,T4,T5) a T2 b T3 c T4 d T5

T1 bool T1 T1

The else node should be of the same type as the if node

slide-26
SLIDE 26

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int

f T1(*)(T2,int,T4,T5) a T2 b int c T4 d T5

The operands of a comparison

  • perator (=) should be of the same
  • type. The right operand is int, so b

should be int too i.e. T3 = int

slide-27
SLIDE 27

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool

f T1(*)(T2,int,T4,T5) a T2 b int c T4 d T5

The condition should be of type boolean

slide-28
SLIDE 28

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T4,T5) a T2 b int c T4 d T5

The then node should be of the same type as the if node

slide-29
SLIDE 29

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T4,T5) a T2 b int c T4 d T5

T1

The else node should be of the same type as the if node

slide-30
SLIDE 30

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T4,T5) a T2 b int c T4 d T5

T1 bool

The condition should be of type boolean

slide-31
SLIDE 31

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T4,T5) a T2 b int c T4 d T5

T1 bool T1

The then node should be of the same type as the if node

slide-32
SLIDE 32

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T4,T5) a T2 b int c T4 d T5

T1 bool T1 T1

The else node should be of the same type as the if node

slide-33
SLIDE 33

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T4,T5) a T2 b int c T4 d T5

T1 bool T1 T1 bool(*)(int) int

The left-most child node of an apply node must be a function, the other children are the parameters passed to that

  • function. The return type of the function is

the type of the apply node

slide-34
SLIDE 34

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T1(*)(int),T5) a T2 b int c T1(*)(int) d T5

T1 bool T1 T1 bool(*)(int) int int T1(*)(int)

c must be a function that takes one integer argument and returns a value of type T1, i.e. T4 = T1(*)(int)

slide-35
SLIDE 35

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T1(*)(int),int) a T2 b int c T1(*)(int) d int

T1 bool T1 T1 bool(*)(int) int int T1(*)(int) int

We know that c is a function that takes an integer as argument and returns

  • T1. The argument passed here is d, so d

must be of type int, i.e. T5 = int

slide-36
SLIDE 36

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T1(*)(int),int) a T2 b int c T1(*)(int) d int

T1 bool T1 T1 bool(*)(int) int int T1(*)(int) int int bool(*)(int)

The type of [] node must be a function that takes an integer as argument and returns boolean, i.e. bool(*)(int)

slide-37
SLIDE 37

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T1(*)(int),int) a T2 b int c T1(*)(int) d int

T1 bool T1 T1 bool(*)(int) int int T1(*)(int) int int bool(*)(int)

We know that c is a function that takes an integer as argument and returns T1, we also know that b is integer

slide-38
SLIDE 38

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(T2,int,T1(*)(int),int) a T2 b int c T1(*)(int) d int

T1 bool T1 T1 bool(*)(int) int int T1(*)(int) int int bool(*)(int) int

We know that f is a function that takes 4 arguments of types T2, int, T1(*)(int) and int and returns a value of type T1. We know that a is of type T2, and c is of type T1(*)(int) and d is of type int. The - node should be of type int

slide-39
SLIDE 39

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(array(bool(*)(int)),int,T1(*)(int),int) a array(bool(*)(int)) b int c T1(*)(int) d int

T1 bool T1 T1 bool(*)(int) int int T1(*)(int) int int bool(*)(int) int

Since the indexing operator is applied to a, it must be an array. Each element of the array should be the same type as the [] node, i.e. T2 = array(bool(*)(int))

slide-40
SLIDE 40

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(array(bool(*)(int)),int,T1(*)(int),int) a array(bool(*)(int)) b int c T1(*)(int) d int

T1 bool T1 T1 bool(*)(int) int int T1(*)(int) int int bool(*)(int) int

b is used as an index value, it must be int (we already know that —> no conflict). Also a must be an array of bool(*)(int) which is consistent with what we already inferred

slide-41
SLIDE 41

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(array(bool(*)(int)),int,T1(*)(int),int) a array(bool(*)(int)) b int c T1(*)(int) d int

T1 bool T1 T1 bool(*)(int) int int T1(*)(int) int int bool(*)(int) int

b is an operand of an arithmetic

  • peration involving an integer (1), so it must

be int which is consistent with what we already

  • inferred. Also the type of - node is consistent

with the types of operands

slide-42
SLIDE 42

f(a,b,c,d) def if = b 1 if if apply [] a 1 apply 1 c apply d c apply [] a b apply b c apply f a

  • b

1 c d

T1 bool T1 T1 int int bool T1

f T1(*)(array(bool(*)(int)),int,T1(*)(int),int) a array(bool(*)(int)) b int c T1(*)(int) d int

T1 bool T1 T1 bool(*)(int) int int T1(*)(int) int int bool(*)(int) int

slide-43
SLIDE 43

g(a,b,c) = if a(1) = 3.5 then b - 1 else if c[5] < a(0) then else g(a, b * 2, c)

Example #2

slide-44
SLIDE 44

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g T1(*)(T2,T3,T4) a T2 b T3 c T4

slide-45
SLIDE 45

Bottom-Up order

slide-46
SLIDE 46

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g T1(*)(T2,int,T4) a T2 b int c T4

b must be an integer, i.e. T3 = int

int int int

slide-47
SLIDE 47

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g T1(*)(T5(*)(int),int,T4) a T5(*)(int) b int c T4

a must be a function that takes an integer as argument and we don’t know its return type yet, i.e. T2 = T5(*)(int)

int int int T5(*)(int) T5

slide-48
SLIDE 48

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g T1(*)(T5(*)(int),int,array(T6)) a T5(*)(int) b int c array(T6)

c must be an array since it is the left child of an indexing node. The type

  • f the elements of the array

are not known yet, i.e. T4 = array(T6)

int int int T5(*)(int) T5 array(T6) T6

slide-49
SLIDE 49

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g T1(*)(T5(*)(int),int,array(T5)) a T5(*)(int) b int c array(T5)

The operands of a comparison operator must be of the same type, i.e. T6 = T5

int int int T5(*)(int) T5 array(T5) T6 = T5

slide-50
SLIDE 50

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g T1(*)(T5(*)(int),int,array(T5)) a T5(*)(int) b int c array(T5)

Recursive call to g with no conflict. The type of the apply node must be the same as return type of g, i.e. T1

int int int T5(*)(int) T5 array(T5) T5 T1

slide-51
SLIDE 51

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g T1(*)(T5(*)(int),int,array(T5)) a T5(*)(int) b int c array(T5)

int int int T5(*)(int) T5 array(T5) T5 T1

We know that a is a function that takes a single integer argument and returns a value of type T5

T5

slide-52
SLIDE 52

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g T1(*)(float(*)(int),int,array(float)) a float(*)(int) b int c array(float)

int int int float(*)(int) float array(float) float T1

The operands of a comparison operator must be

  • f the same type, so T5

should be float

T5=float float

slide-53
SLIDE 53

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g T1(*)(float(*)(int),int,array(float)) a float(*)(int) b int c array(float)

int int int float(*)(int) float array(float) float T1

b is already known to be of type int, no conflict. Also the type of the “-” node must be int

float float int

slide-54
SLIDE 54

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g int(*)(float(*)(int),int,array(float)) a float(*)(int) b int c array(float)

int int int float(*)(int) float array(float) float T1 = int float float int bool int int

The condition of an if node must be of type boolean which it is. The then and else nodes must have the same type as the if node. So T1 = int

slide-55
SLIDE 55

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g int(*)(float(*)(int),int,array(float)) a float(*)(int) b int c array(float)

int int int float(*)(int) float array(float) float int float float int bool int int int bool

The condition of an if node must be of type boolean which it is. The then and else nodes must have the same type as the if node. No conflict

slide-56
SLIDE 56

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g int(*)(float(*)(int),int,array(float)) a float(*)(int) b int c array(float)

int int int float(*)(int) float array(float) float int float float int bool int int int bool

The return type of the function g must be the same as the type of the if node which it is —> No conflict

slide-57
SLIDE 57

g(a,b,c) def if = a 3.5 if apply g a * b 2 c apply 1 b 1

  • <

[] c 5 a apply

g int(*)(float(*)(int),int,array(float)) a float(*)(int) b int c array(float)

int int int float(*)(int) float array(float) float int float float int bool int int int bool

slide-58
SLIDE 58

h(x,y,z) = if x > 1 then y * 2.0 else z + h(y, x, z)

Example #3

slide-59
SLIDE 59

h(x,y,z) def if > x + apply h y x z 1 y 2.0 * z

h T1(*)(T2,T3,T4) x T2 y T3 z T4

slide-60
SLIDE 60

Random order

slide-61
SLIDE 61

h(x,y,z) def if > x + apply h y x z 1 y 2.0 * z

h T1(*)(T2,float,T4) x T2 y float z T4

y must be float since it is used in an arithmetic operation involving 2.0, hence T3 = float

float float float

slide-62
SLIDE 62

h(x,y,z) def if > x + apply h y x z 1 y 2.0 * z

h T1(*)(T2,float,T4) x T2 y float z T4

The condition node must be boolean and the then and else nodes should be of the same type as the if node

float float float float float bool

slide-63
SLIDE 63

h(x,y,z) def if > x + apply h y x z 1 y 2.0 * z

h float(*)(T2,float,T4) x T2 y float z T4

The return type of h must be the same as the type of the if node, i.e. T1 = float

float float float float float bool

slide-64
SLIDE 64

h(x,y,z) def if > x + apply h y x z 1 y 2.0 * z

h float(*)(int,float,T4) x int y float z T4

float float float float float bool

x must be int since it is compared with integer constant 1, i.e. T2 = int

int

slide-65
SLIDE 65

h(x,y,z) def if > x + apply h y x z 1 y 2.0 * z

h float(*)(int,float,float) x int y float z float

float float float float float bool

z must be float since the result of the arithmetic operation is

  • f type float. Also the apply node

must be of type float

int float float

slide-66
SLIDE 66

h(x,y,z) def if > x + apply h y x z 1 y 2.0 * z

h float(*)(int,float,float) x int y float z float

float float float float float bool int float float float float int float(*)(int,float,float)

Call to h with the following argument types: float, int, float —> Type Mismatch

slide-67
SLIDE 67

Type Constraints

slide-68
SLIDE 68

Function Definitions

def function body

T T(*)(…)

slide-69
SLIDE 69

If-Then-Else

if Condition Else Then

bool T T T

slide-70
SLIDE 70

Arithmetic Expressions

  • p

left right

T T T

  • p must be an arithmetic
  • perator: + - * /
slide-71
SLIDE 71

Comparisons

  • p

left right

bool T T

  • p must be a comparison
  • perator: < > = <= etc.
slide-72
SLIDE 72

Function Calls

apply function param1

T1

param2 param3

T2 T3 … T0(*)(T1,T2,T3,…) T0

slide-73
SLIDE 73

Array Indexing

[] array index

int array(T) T