15 150 fall 2020
play

15-150 Fall 2020 Lecture 10 Stephen Brookes Type checking Type - PowerPoint PPT Presentation

15-150 Fall 2020 Lecture 10 Stephen Brookes Type checking Type inference Polymorphism type benefits ... a static check provides a runtime guarantee static property runtime guarantee e has type t if e =>* v then v : t d


  1. 15-150 Fall 2020 Lecture 10 Stephen Brookes • Type checking • Type inference • Polymorphism

  2. type benefits ... a static check provides a runtime guarantee static property runtime guarantee e has type t if e =>* v then v : t d declares x : t if d =>* [x : v] then v : t

  3. advantages would be expensive Type analysis is easy , static , cheap to keep checking at runtime • A type error indicates a bug detected, and prevented, without running code • An unexpected type may also indicate a bug ! Values of a given type have predictable form • We can use appropriate patterns and design code accordingly Type information can guide specs and proofs

  4. Referential transparency for types How to tell statically when e : t • The type of an expression depends on the types of its sub-expressions ... hence, the type of an expression depends on its syntactic form and the types of its free variables x + x has type int if x has type int x + x has type real if x has type real ( fn x:int => x+x) e has type int if e has type int ( fn x:int => x+x) true is not well typed

  5. type analysis can be done statically , at parse time • There are syntax-directed rules for figuring out when e has type t e is well-typed, with type t, if and only if provable from these rules … possibly with We say “e has type t” assumptions like or write “e : t” “x:int and y:int”

  6. Typing rules There are syntax-directed rules for “judgements” e has type t d declares x 1 : t 1 … x k : t k p matches type t and binds x 1 : t 1 … x k : t k under appropriate assumptions about the free variables of e and d

  7. type checking • Use the typing rules to check that (given specific types for variables) e has type t type inference • Use the typing rules to figure out (given partial information about variables) if e is well-typed, and — if so — its most general type

  8. arithmetic • a numeral n has type int • e 1 + e 2 has type int if e 1 and e 2 have type int • Similarly for e 1 * e 2 and e 1 - e 2 static property runtime behavior 21 + 21 has type int 21 + 21 ⟹ * 42 : int

  9. booleans • true and false have type bool • e 1 andalso e 2 has type bool similarly for if e 1 and e 2 have type bool e 1 orelse e 2 • e 1 < e 2 has type bool similarly for e 1 <= e 2 if e 1 and e 2 have type int e 1 > e 2 static property runtime behavior (3+4 < 1+7) : bool (3+4 < 1+7) ⟹ * true : bool

  10. conditional (for each type t) • if e then e 1 else e 2 has type t if e has type bool and e 1 , e 2 have type t test must be a boolean, both branches must have the same type runtime static if x<y then x else y ⟹ * 4 : int if x<y then x else y has type int if x:4 and y:5 if x: int and y: int

  11. tuples (for all types t 1 and t 2 ) • (e 1 , e 2 ) has type t 1 * t 2 if e 1 has type t 1 and e 2 has type t 2 static runtime (x+2, y) has type int * bool (x+2, y) ⟹ * (4, true) : int * bool when x:int and y:bool when x:2 and y:true Similarly for (e 1 , ..., e k ) when k>0 Also ( ) has type unit

  12. lists (for each type t) • [e 1 , ..., e n ] has type t list all items in a list if for each i, e i has type t must have the same type • e 1 ::e 2 has type t list if e 1 has type t and e 2 has type t list • e 1 @e 2 has type t list if e 1 and e 2 have type t list [1+2, 3+4] has type int list [1+2, 3+4] ⟹ * [3, 7] : int list

  13. functions • fn x => e has type t 1 -> t 2 the type of a function ensures type-safe if e has type t 2 when x : t 1 application when applied to an argument of type t 1 the result will have type t 2 fn x => x+x has type int -> int fn x => x+x has type real -> real fn y => x+y has type int -> int when x:int

  14. application • e 1 e 2 has type t 2 if e 1 has type t 1 -> t 2 and e 2 has type t 1 argument e 2 must have correct type for function e 1 (fn x => x+x) (10+11) has type int (fn x => x+x) (1.0+1.1) has type real

  15. example fn x => if x=0 then 1 else f(x-1) has type int -> int if f : int -> int by rules for fn x => e if-then-else application …

  16. declarations • val x = e declares x : t if e has type t val x = 42 declares x : int val x = y+y declares x : int if y : int val f = fn x => x + 1 declares f : int -> int

  17. declarations If d 1 declares x 1 :t 1 and (with this type for x 1 ) d 2 declares x 2 :t 2 then d 1 ;d 2 declares x 1 :t 1 , x 2 :t 2 val y = 21; declares y:int, x:int val x = y+y

  18. declarations • fun f x = e declares f : t 1 -> t 2 if, assuming x : t 1 and f : t 1 -> t 2 , e has type t 2 assuming that the result of and f is applied to e recursive calls to f in e an argument of type t 1 will have type t 2 have type t 1 -> t 2 fun f x = if x=0 then 1 else f(x-1) declares f : int -> int … binds f to a function value of type int -> int

  19. let expressions • let d in e end has type t if d declares x 1 : t 1 , ..., x k : t k and, in the scope of these bindings e has type t let val x = 21 in x + x end has type int and evaluates to 42 : int let has type int fun f x = if x=0 then 1 else f(x-1) and evaluates to 1 : int in f 42 end

  20. patterns when p matches type t • _ matches t always • 42 matches t iff t is int • x matches t always (binds x : t) • (p 1 , p 2 ) matches t iff (combine t is t 1 * t 2 , p 1 matches t 1 , p 2 matches t 2 bindings from p 1 • p 1 ::p 2 matches t iff and p 2 ) t is t 1 list, p 1 matches t 1 , p 2 matches t 1 list

  21. examples • Pattern x::R matches type int list and binds x:int, R:int list • Pattern x::R matches type bool list and binds x:bool, R:bool list • Pattern 42::R matches type int list and binds R:int list

  22. clausal functions • fn p 1 => e 1 | ... | p k => e k has type t 1 -> t 2 if for each i, p i matches t 1 and produces bindings that give e i type t 2 each clause p i => e i must have same type t 1 -> t 2 - each p i must match type t 1 - each e i must have type t 2 fn 0 => 0 | n => f(n - 1) has type int -> int if f has type int -> int

  23. clausal declarations • fun f p 1 = e 1 | ... | f p k = e k declares f : t 1 -> t 2 if for i = 1 to k, p i matches t 1 , giving type bindings for which, assuming f : t 1 -> t 2 , e i has type t 2 each clause p i => e i must have same type t 1 -> t 2 assuming recursive calls to f in e i have this type fun f 0 = 0 | f n = f (n - 1) declares f : int -> int … and binds f to a value of type int -> int

  24. example fun f n = if n=0 then 1 else n + f (n - 1) declares f : int -> int because, assuming n : int and f : int -> int, if n=0 then 1 else n + f (n - 1) has type int

  25. Polymorphic types • ML has type variables ’a, ’b, ’c • A type with type variables is polymorphic ’a list -> ’a list • A polymorphic type has instances substitute a type for each type variable int list -> int list real list -> real list (int * real) list -> (int * real) list ... instances of ’a list -> ’a list

  26. typability • t is a type for e iff (e has type t) is provable • In the scope of d, x has type t iff (d declares x:t) is provable int list -> int list is a type for rev real list -> real list is a type for rev ’a list -> ’a list is a type for rev

  27. Instantiation • If e has type t, and t ’ is an instance of t, then e also has type t ’ An expression can be used at any instance of its type

  28. Most general types Every well-typed expression has a most general type t is a most general type for e iff t is a type for e & every type for e is an instance of t rev has most general type ’a list -> ’a list

  29. type inference • ML computes most general types • statically, using syntax as guide Standard ML of New Jersey v110.75 - fun rev [ ] = [ ] | rev (x::L) = (rev L) @ [x]; val rev = fn : 'a list -> 'a list

  30. benefits • Types can guide program design • Type errors may indicate bug in code • An unexpected type may also indicate a bug

  31. split fun split [ ] = ([ ], [ ]) | split [x] = ([x], [ ]) | split (x::y::L) = let val (A,B) = split L in (x::A, y::B) end declares split : int list -> int list * int list also (more generally!) declares split : ’a list -> ’a list * ’a list (the most general type is polymorphic)

  32. sorting Assuming split : ’a list -> ’a list * ’a list merge : int list * int list -> int list fun msort [ ] = [ ] | msort [x] = [x] | msort L = let val (A,B) = split L in merge (msort A, msort B) end declares msort : int list -> int list (earlier, we proved correctness of this function)

  33. sorting Assuming split : ’a list -> ’a list * ’a list merge : int list * int list -> int list fun msort [ ] = [ ] | msort L = let val (A,B) = split L in merge(msort A, msort B) end declares msort : ’a list -> int list An unexpected type… there’s a bug in the code! Reason: the type guarantee… tells us that msort L doesn’t terminate when L is non-empty!

  34. polymorphic values? [ ] is the only value of type ’a list Every type has a set of syntactic values • What are the values of type ’a -> ’a ? fn x => x fn x => loop( ) (all are equivalent to) or • What are the values of type ’a ? There are none! Reason: the type guarantee

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend