Slide 1

Slide 1 text

Type Inference How Does it Work? Ionuț G. Stan — Bucharest FP #9 — March 2015

Slide 2

Slide 2 text

Organization • Compilers Overview • Overview of the Damas-Hindley-Milner Algorithm • Code • Limitations of Damas-Hindley-Milner

Slide 3

Slide 3 text

Compilers Overview

Slide 4

Slide 4 text

Compilers Overview Code Emitter Target Source

Slide 5

Slide 5 text

Compilers Overview Code Emitter Target Source Parser Code Emitter Target Source

Slide 6

Slide 6 text

Compilers Overview Code Emitter Target Source Parser Code Emitter Target Source AST (Abstract Syntax Tree)

Slide 7

Slide 7 text

Compilers Overview Code Emitter Target Source Parser Code Emitter Target Source Parser Type Checker Source Target Code Emitter AST (Abstract Syntax Tree)

Slide 8

Slide 8 text

Compilers Overview Code Emitter Target Source Parser Code Emitter Target Source Parser Type Checker Source Target Code Emitter Parser Type Checker Source Target Code Emitter ...

Slide 9

Slide 9 text

Today Parser Type Checker ... Source AST (Abstract Syntax Tree) Target

Slide 10

Slide 10 text

Algorithm Overview

Slide 11

Slide 11 text

Algorithm Overview • Phase 1: source code → parse → abstract syntax tree (AST) • Phase 2: AST → annotate → typed abstract syntax tree (TST) • Phase 3: TST → generate constraints → constraint list • Phase 4: constraint list → unify → solution list

Slide 12

Slide 12 text

Algorithm Overview • Phase 1: source code → parse → abstract syntax tree (AST) • Phase 2: AST → annotate → typed abstract syntax tree (TST) • Phase 3: TST → generate constraints → constraint list • Phase 4: constraint list → unify → solution list

Slide 13

Slide 13 text

Algorithm Overview • Phase 1: source code → parse → abstract syntax tree (AST) • Phase 2: AST → annotate → typed abstract syntax tree (TST) • Phase 3: TST → generate constraints → constraint list • Phase 4: constraint list → unify → solution list

Slide 14

Slide 14 text

Algorithm Overview • Phase 1: source code → parse → abstract syntax tree (AST) • Phase 2: AST → annotate → typed abstract syntax tree (TST) • Phase 3: TST → generate constraints → constraint list • Phase 4: constraint list → unify → solution list

Slide 15

Slide 15 text

Running Example let val inc = fn n => n + 1 in inc 42 end

Slide 16

Slide 16 text

Phase 1: Abstract Syntax Tree let val inc = fn n => n + 1 in inc 42 end LET inc FN n ADD VAR n INT 1 APP VAR inc INT 42

Slide 17

Slide 17 text

Phase 2: Explicit Type Annotations LET inc FN n ADD VAR n INT 1 APP VAR inc INT 42 LETt3 inc FNt1 !int a ADDint VARt1 a INTint 1 APPt2 VARt1 !int inc INTint 42

Slide 18

Slide 18 text

Phase 3: Constraint Generation LETt3 inc FNt1 !int a ADDint VARt1 a INTint 1 APPt2 VARt1 !int inc INTint 42

Slide 19

Slide 19 text

Phase 3: Constraint Generation LETt3 inc FNt1 !int a ADDint VARt1 a INTint 1 APPt2 VARt1 !int inc INTint 42 t1 → int = int → t2

Slide 20

Slide 20 text

Phase 3: Constraint Generation LETt3 inc FNt1 !int a ADDint VARt1 a INTint 1 APPt2 VARt1 !int inc INTint 42 t1 → int = int → t2 int = int

Slide 21

Slide 21 text

Phase 3: Constraint Generation LETt3 inc FNt1 !int a ADDint VARt1 a INTint 1 APPt2 VARt1 !int inc INTint 42 t1 → int = int → t2 int = int t1 = int

Slide 22

Slide 22 text

Phase 3: Constraint Generation LETt3 inc FNt1 !int a ADDint VARt1 a INTint 1 APPt2 VARt1 !int inc INTint 42 t1 → int = int → t2 int = int t1 = int t3 = t2

Slide 23

Slide 23 text

Phase 3: Constraint Generation LETt3 inc FNt1 !int a ADDint VARt1 a INTint 1 APPt2 VARt1 !int inc INTint 42 t1 → int = int → t2 int = int t1 = int t3 = t2

Slide 24

Slide 24 text

Phase 4: Unification

Slide 25

Slide 25 text

Phase 4: Unification f(x) = f(g(y)) [x: g(y)]

Slide 26

Slide 26 text

Phase 4: Unification f(x) = f(g(y)) [x: g(y)] f(x, g(3)) = f(g(y), x) [x: g(y); y: 3]

Slide 27

Slide 27 text

Phase 3: Constraint Generation LETt3 inc FNt1 !int a ADDint VARt1 a INTint 1 APPt2 VARt1 !int inc INTint 42 t1 → int = int → t2 int = int t1 = int t3 = t2

Slide 28

Slide 28 text

Phase 4: Unification t1 → int = int → t2 int = int t1 = int t3 = t2

Slide 29

Slide 29 text

Phase 4: Unification t1 → int = int → t2 int = int t1 = int t3 = t2 3 = t2

Slide 30

Slide 30 text

Phase 4: Unification t1 → int = int → t2 int = int t1 = int 3 = t2

Slide 31

Slide 31 text

Phase 4: Unification t1 → int = int → t2 int = int 3 = t2 1 = int

Slide 32

Slide 32 text

Phase 4: Unification int → int = int → t2 int = int 3 = t2 1 = int

Slide 33

Slide 33 text

Phase 4: Unification int → int = int → t2 3 = t2 1 = int

Slide 34

Slide 34 text

Phase 4: Unification int → t2 int → int 3 = t2 1 = int

Slide 35

Slide 35 text

Phase 4: Unification int → t2 3 = t2 1 = int

Slide 36

Slide 36 text

Phase 4: Unification 3 = t2 1 = int 2 = int

Slide 37

Slide 37 text

Phase 4: Unification 3 = int 1 = int 2 = int

Slide 38

Slide 38 text

Code

Slide 39

Slide 39 text

https://github.com/igstan/damas-hindley-milner

Slide 40

Slide 40 text

Limitations

Slide 41

Slide 41 text

Limitations • doesn't work with OOP; subtyping breaks unification • restricted let-polymorphism with mutable references (ref) • polymorphic params (rank-n polymorphism) • algorithm complexity is exponential; not a problem in practice

Slide 42

Slide 42 text

Value Restriction in SML val r0 : 'a option ref = ref NONE val r1 : string option ref = r0 val r2 : int option ref = r0 val _ = r1 := SOME "foo" val v : int = valOf (!r2)

Slide 43

Slide 43 text

Value Restriction in SML val r0 : 'a option ref = ref NONE val r1 : string option ref = r0 val r2 : int option ref = r0 val _ = r1 := SOME "foo" val v : int = valOf (!r2) The string inside is used as an int. ERROR

Slide 44

Slide 44 text

Value Restriction in SML val r0 : 'a option ref = ref NONE val r1 : string option ref = r0 val r2 : int option ref = r0 val _ = r1 := SOME "foo" val v : int = valOf (!r2) Solved in OCaml using weak polymorphism. Type is polymorphic until first use; afterwards becomes monomorphic. ERROR

Slide 45

Slide 45 text

Rank-N Polymorphism fn id => (id 1, id true) Parameters are not polymorphic. Algorithm becomes undecidable. let val id = fn a => a in (id 1, id true) end OK ERROR

Slide 46

Slide 46 text

Exponential Time http://spacemanaki.com/blog/2014/08/04/Just-LOOK-at-the-humongous-type/ fn _ => let val id = fn a => a val d1 = (id, id) val d2 = (d1, d1) val d3 = (d2, d2) val d4 = (d3, d3) val d5 = (d4, d4) val d6 = (d5, d5) in d6 end

Slide 47

Slide 47 text

Exponential Time http://spacemanaki.com/blog/2014/08/04/Just-LOOK-at-the-humongous-type/ val it = fn : 'a -> (((((('b -> 'b) * ('c -> 'c)) * (('d -> 'd) * ('e -> 'e))) * ((('f -> 'f) * ('g -> 'g)) * (('h -> 'h) * ('i -> 'i)))) * (((('j -> 'j) * ('k -> 'k)) * (('l -> 'l) * ('m -> 'm))) * ((('n -> 'n) * ('o -> 'o)) * (('p -> 'p) * ('q -> 'q))))) * ((((('r -> 'r) * ('s -> 's)) * (('t -> 't) * ('u -> 'u))) * ((('v -> 'v) * ('w -> 'w)) * (('x -> 'x) * ('y -> 'y)))) * (((('z -> 'z) * ('ba -> 'ba)) * (('bb -> 'bb) * ('bc -> 'bc))) * ((('bd -> 'bd) * ('be -> 'be)) * (('bf -> 'bf) * ('bg -> 'bg)))))) * (((((('bh -> 'bh) * ('bi -> 'bi)) * (('bj -> 'bj) * ('bk -> 'bk))) * ((('bl -> 'bl) * ('bm -> 'bm)) * (('bn -> 'bn) * ('bo -> 'bo)))) * (((('bp -> 'bp) * ('bq -> 'bq)) * (('br -> 'br) * ('bs -> 'bs))) * ((('bt -> 'bt) * ('bu -> 'bu)) * (('bv -> 'bv) * ('bw -> 'bw))))) * ((((('bx -> 'bx) * ('by -> 'by)) * (('bz -> 'bz) * ('ca -> 'ca))) * ((('cb -> 'cb) * ('cc -> 'cc)) * (('cd -> 'cd) * ('ce -> 'ce)))) * (((('cf -> 'cf) * ('cg -> 'cg)) * (('ch -> 'ch) * ('ci -> 'ci))) * ((('cj -> 'cj) * ('ck -> 'ck)) * (('cl -> 'cl) * ('cm -> 'cm))))))

Slide 48

Slide 48 text

Exponential Time http://spacemanaki.com/blog/2014/08/04/Just-LOOK-at-the-humongous-type/

Slide 49

Slide 49 text

Thank You!