Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Type Inference: How Does it Work?

Type Inference: How Does it Work?

Bucharest FP

March 31, 2015
Tweet

More Decks by Bucharest FP

Other Decks in Programming

Transcript

  1. Compilers Overview Code Emitter Target Source Parser Code Emitter Target

    Source Parser Type Checker Source Target Code Emitter AST (Abstract Syntax Tree)
  2. 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 ...
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. Phase 3: Constraint Generation LETt3 inc FNt1 !int a ADDint

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

    VARt1 a INTint 1 APPt2 VARt1 !int inc INTint 42 t1 → int = int → t2
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. Phase 4: Unification t1 → int = int → t2

    int = int t1 = int t3 = t2 3 = t2
  17. 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
  18. 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)
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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))))))