2
Software is hard to get right* Which tools can help programmers write reliable code? How to make these tools more practical and effective to use? 1 Making programming language types more practical and effective Making programming language types more practical and effective * Toyota recalls 2010 models due to faulty software in the brakes. Upgrade your Prius! this talk

13
Type checking and GADTs 12 Pattern matching introduces type equalities, available after the =  In the first branch we learn that a ~ Int data Term a where ILit :: Int -> Term Int eval :: Term a -> a eval (ILit i) = i eval _ = … i :: Int Possible with the help of programmer annotations Right-hand side: we must return type a Right-hand side: we must return type a That’s fine because we know that (a~Int) from pattern matching That’s fine because we know that (a~Int) from pattern matching Determines the term we analyze Determines the result

14
Type inference and GADTs 13 Here is a possible type of getILit : Term a -> [Int] But if (a ~ Int) is used then there is also another one Term a -> [a] data Term a where ILit :: Int -> Term Int... -- Get a list of literals in this term getILit (ILit i) = [i] getILit _ = [] Haskell programmers omit type signatures BAD!

15
A threat for modularity 14 Two different “specifications” for getILit btrm :: Term Bool f1 = (getILit btrm) ++ [0] f2 = (getILit btrm) ++ [True] test = let getILit (ILit i) = [i] getILit _ = [] in... Works only with: Term a -> [Int] Works only with: Term a -> [a] And this one? We want to have a unique principal type that we infer once and use throughout the scope of the function

17
Discovering a complete implementation 16 Predictability mandates high-level declarative typing rules That turned out to be possible because: 1. Typing rules [and algorithm] can “switch” mode when they meet annotations 2. The GADT checking problem is easy 3. All non-GADT branches are typed as in Hindley-Milner  This is what GHC implements since 2006  Extremely effective and popular: http://darcs.net, commercial users, …http://darcs.net The first work on type inference and GADTs to achieve this The first work on type inference and GADTs to achieve this Theorem: There exists a provably decidable, sound and complete algorithm for the [ICFP 2006] type system Needed to design a type system and a sound and complete algorithm Needed to design a type system and a sound and complete algorithm

18
[ICFP 2006] was a breakthrough but … 17 To reduce required annotations it used some ad-hoc annotation propagation How to improve this? opt :: Term b -> Term b eval :: Term a -> a eval x = case opt x of ILit i -> i eval :: Term a -> a eval x = let f x = x in case f (opt x) of ILit i -> i fails Because no type annotation for f Quite remarkable BUT what about predictability? typechecks

19
The Outside-In solution 18 Shrijvers, Sulzmann, Peyton Jones, Vytiniotis [ICFP 2009] perform full inference outside a GADT branch first, and then use what you learnt to go inside the branch  Very aggressive type information discovery  + a simpler “Outside-In” type system eval :: Term a -> a eval x = let f x = x in case f (opt x) of ILit i -> i Working on the outside of the branch first determines that f (opt x) :: Term a Working on the outside of the branch first determines that f (opt x) :: Term a

20
Simplifying and reducing annotations [ICFP 2009] 19  Fewer annotations needed  Predictability  Forthcoming implementation in GHC, invited paper in special issue of JFP  “the system of this paper is the simplest proposal ever made to solve type inference for GADTs” [anonymous reviewer] Theorem: There exists a provably decidable, sound and complete algorithm for the “Outside-In” type system in [ICFP 2009] All type-safe programs All programs with principal types Modularity Theorem: “Outside-In” type system

21
Inferring principal types in [ICFP 2009] 20 data Term a where ILit :: Int -> Term Int If :: Term Bool -> Term a -> Term a -> Term a -- Get the least number in this term findLeast (ILit i) = i findLeast (If cond t1 t2) = let x1 = findLeast t1 x2 = findLeast t2 in if (x1 < x2) then x1 else x2 Because of (x1 < x2), f indLeast must return Int. T here is a principal type [and ICFP 2009 finds it]: Term a -> Int Because of (x1 < x2), f indLeast must return Int. T here is a principal type [and ICFP 2009 finds it]: Term a -> Int Not due to arbitrarily choosing Term a -> Int as previously Not due to arbitrarily choosing Term a -> Int as previously REJECTED in [ICFP 2009] No ad-hoc assumptions about programmer intentions REJECTED in [ICFP 2009] No ad-hoc assumptions about programmer intentions

25
The Hindley-Milner type system 25 years later 24 How all the above affect our “golden standard” of modern type systems?  We had to add user type annotations to HM to get GADTs  Yet another reason for this is first-class polymorphism [THESIS TOPIC]  QML: Explicit first-class polymorphism for ML [Russo, Vytiniotis, ML 2009]  FPH: First-class polymorphism for Haskell [Vytiniotis, Peyton Jones, Weirich, ICFP 2008]  Practical type inference for higher-rank types [Peyton Jones, Vytiniotis, Weirich, Shields, JFP 2007]  The canonical reference for Higher-Rank type systems  Boxy Types [Vytiniotis, Peyton Jones, Weirich, ICFP 2006]  … but are we also forced to remove anything? Reminder: Hindley-Milner does not need any annotations, at all Reminder: Hindley-Milner does not need any annotations, at all

26
let generalization in Hindley-Milner 25  For some extensions [e.g. GHCs celebrated type families] we must allow deferring because: no-deferring hard-to-generalize* … but is it practical to defer? main = let group x y = [x,y] in (group 0 1, group False False) group is polymorphic. We can give it the generalized type group :: forall a. a -> a -> [a] or defer the check to the call sites [Pottier, Sulzmann, HM(X)]: group :: forall a b. (a ~ b) => a -> b -> [a] group is polymorphic. We can give it the generalized type group :: forall a. a -> a -> [a] or defer the check to the call sites [Pottier, Sulzmann, HM(X)]: group :: forall a b. (a ~ b) => a -> b -> [a] * trust me

28
The proposal [TLDI 2010] 27  D. Vytiniotis, S. Peyton Jones, T. Schrijvers [TLDI 2010] Abandon generalization of local definitions  The only complete algorithms are not practical RADICAL: removing a basic ingredient of HM But not restrictive in practice: 127 lines affected in 95Kloc of Haskell libraries (0.13%)! No expressivity loss: Polymorphism can be recovered with annotations RADICAL: removing a basic ingredient of HM But not restrictive in practice: 127 lines affected in 95Kloc of Haskell libraries (0.13%)! No expressivity loss: Polymorphism can be recovered with annotations

30
OutsideIn(X) – new JFP submission 29  Substantial article that brings the results of a multi-year collaborative research program together  Many people involved over the years: Simon Peyton Jones, Tom Schrijvers (KU Leuven), Martin Sulzmann (Informatik Consulting Systems AG), Manuel Chakravarty (UNSW), Stephanie Weirich (Penn), Geoff Washburn (LogicBlox), …  Bonus: a new glorious constraint solver to instantiate X, which improves previous work, and for the first time shows how to deal with all of GHCs tricky features

35
Q-A games for encoding and decoding 34 Imagine a binary format such that every bitstring encodes a non-empty set of type-safe CIL programs Not easy to program from first principle!  Instead, understand and program encoders using question-answer games  Good coding scheme follows by asking good questions!  Recent ICFP 2010 submission with A. Kennedy y y y n n n

36
Programming language types Making good software easier to write 35 complexity # bugs A demonstrably simple technology that can already eliminate lots of bugs This talk: solving research problems to make types more effective and practical: Catch more bugs Require little user guidance Remain predictable and modular This talk: solving research problems to make types more effective and practical: Catch more bugs Require little user guidance Remain predictable and modular