Let should not be generalized Dimitrios Vytiniotis, Simon Peyton Jones Microsoft Research, Cambridge TLDI’1 0, Madrid, January 2010 Tom Schrijvers K.U.

Download Let should not be generalized Dimitrios Vytiniotis, Simon Peyton Jones Microsoft Research, Cambridge TLDI’1 0, Madrid, January 2010 Tom Schrijvers K.U.

Post on 14-Jan-2016

212 views

Category:

Documents

0 download

Embed Size (px)

TRANSCRIPT

<p>Implementing type inference for first-class polymorphism</p> <p>let should not be generalizedDimitrios Vytiniotis, Simon Peyton Jones Microsoft Research, CambridgeTLDI10, Madrid, January 2010Tom SchrijversK.U. LeuvenExtending ML type inference with 1Advanced types Generalized Algebraic Datatypes (GADTs) [Cheney &amp; Hinze, Xi, Peyton Jones et al., Pottier &amp; Simonet, Pottier &amp; Regis-Gianas,]Open Type Families [Schrijvers et al., ICFP 2007] types indexed by some constraint domain [e.g. Kennedys types indexed by Units of Measure, ESOP94]</p> <p>Advanced forms of constraintsType equalities with type families, type class constraintsImplication constraints that arise because of pattern matching[Pottier &amp; Regis-Gianas, Sulzmann et al.]</p> <p>A question: How should we be generalizing let-bound definitions?</p> <p>Why is this question relevant? 2Type system decisions (as let-generalization) affectImplementability of type inference &amp; checking Complexity of implementationEfficiency of implementationProgrammabilityPredictability of type checkingBackwards compatibility (lots of Haskell 98 code!) </p> <p>GOAL: Support advanced forms of types and constraints mentionedPerform well in (1 6)</p> <p>Generalized Algebraic Datatypes 3 </p> <p>(a ~ Int) =&gt; (Int ~ a)(a ~ Bool) =&gt; (Bool ~ a)GADT data constructors introduce constraints Pattern matching creates implication constraints That a solver must discharge </p> <p>data R a where Rint :: (a ~ Int) =&gt; R a Rbool :: (a ~ Bool) =&gt; R a</p> <p>create :: R a -&gt; a create Rint = 42 create Rbool = False </p> <p>Constraint introduced by Rint42 : Int Expected type: aGADTs and Generalization 4 </p> <p>Observation:(flop 43) and (flop False) can potentially reach first or second branch No DEAD code in the example * data R a where Rint :: (a ~ Int) =&gt; R a Rbool :: (a ~ Bool) =&gt; R a</p> <p>mkR :: a -&gt; R a </p> <p>flop x = let g () = not x -- not :: Bool -&gt; Bool in case (mkR x) of Rbool -&gt; g () Rint -&gt; True x : ~ BoolmkR x : R ~ Bool =&gt; ? ~ Int =&gt; true GADTs and Generalization 5 </p> <p>What is the type of g? If spec does not allow quantification over equalities () -&gt; BoolIf spec does allow quantification over equalities () =&gt; Bool or ( ~ Bool) =&gt; () -&gt; Bool data R a where Rint :: (a ~ Int) =&gt; R a Rbool :: (a ~ Bool) =&gt; R a</p> <p>mkR :: a -&gt; R a </p> <p>flop x = let g () = not x -- not :: Bool -&gt; Bool in case (mkR x) of Rbool -&gt; g () Rint -&gt; True x : ~ BoolmkR x : R ~ Bool =&gt; ? ~ Int =&gt; true Quantifying over equalities 6 </p> <p>data R a where Rint :: (a ~ Int) =&gt; R a Rbool :: (a ~ Bool) =&gt; R a</p> <p>mkR :: a -&gt; R a </p> <p>flop x = let g () = not x -- not :: Bool -&gt; Bool in case (mkR x) of Rbool -&gt; g () Rint -&gt; True Option 1I = Boolg :: () -&gt; Bool</p> <p> Option I g :: ~ Bool =&gt; () -&gt; Bool g :: () -&gt; BoolSecond branch rejected (Bool =/= Int) or typeable as unreachableHence, for GADTs: 7We want to unify away as much as possible (type of x) For simpler typesFor support for some eager solvingFor shorter constraints </p> <p>But we cant unify variables bound in the environment!</p> <p>if the type system allows quantification over equalities then we must defer a lot of silly unifications as constraints</p> <p>Open type families8Programmers declare type-level computations</p> <p>And give axiom schemes for themforall (b).G b Int ~ b In GHC the axiom scheme definitions are openIf G Bool ~ Bool we must not conclude that ~ Int[think of another consistent axiom G Bool Char ~ Bool] type family G a b type instance G b Int = b</p> <p>Quantifying restricted constraints?9Ok, if equalities are problematic quantify over:Class constraints: Eq Type family constraints: F ~ Int</p> <p>Problematic: We want to rewrite as much as possibleBut we must not rewrite too much. Rather delicate!type family G a b type instance G b Int = b</p> <p>flop x = let test = ... in ... x :: Yielding constraint: G Int ~ Int Yielding type: -&gt; G Int ~ &amp; G Int ~ Int which gives ~ IntQuantifying over only class constraints?10Problematic: class constraints may include superclasses:</p> <p>Even if not, its hard to give a complete specification</p> <p>Left-to-right: REJECT (cant discharge constraint)And its not right to defer unsolvable (forall b. F b ~ Int) Right-to-left: ACCEPT Rest of typing problem determines ~ Int and triggers axiom!Class (a ~ b) =&gt; Eq a btype instance F Int b = b </p> <p>let f x = (let h y = (yielding F ~ Int) in 42, x + 42) x :: y :: Let generalization not a new problem really11A. Kennedy knew about it when I was 14! [LIX RR/96/09] </p> <p>Kennedy used a clever domain-specific solutionConstraint equivalent to: v ~ /uype: forall u. Num u -&gt; Num (/u)div :: forall u v. Num (u * v) -&gt; Num u -&gt; Num vweight :: Num kgtime :: Num sec</p> <p>flop x = let y = div x in (y weight, y time)</p> <p>x::Yielding constraint: ~ (u * v)Yielding type: u -&gt; vSolving gives = u * v and g becomes monomorphic!Which IS polymorphic The proposal12The specification and implementation costs for generalizing local let-bound expressions are becoming high:</p> <p>Do NOT Generalize Local Let-Bound Expressions</p> <p>Top-level ones do not contribute to the problems[No environment to interact with]Local but annotated let definitions can be polymorphic</p> <p>Most Haskell 98 programs actually do not use local let polymorphism (though arguably code refactoring tools may). Results performed in Hackage reported in paper</p> <p>Also in paper13Combining Let Should Not Be Generalized with the OutsideIn [ICFP09] strategy for solving implication constraints leads to LHM(X):</p> <p>HM(X) with Local assumptions from pattern matching</p> <p>Type system parameterized over constraint domain X Inference algorithm parameterized over X solverSoundness result provided X solver assumptions </p> <p> towards pluggable type systems + type inference</p> <p>A challenge for type system designers14Solvers for type class and family instance constraints are inherently weak (by design) under an open world assumption</p> <p>Constraint arising: F ~ IntInstance declaration: type instance F Int ~ IntQuestion: What is ? </p> <p>Type system may guess = Int, but algorithm cant [or shouldnt] Challenge: Find a declarative specification that rejects ambiguity</p> <p>A first step: ambiguous constraints15Constraint C is unambiguously solvable in a top-level theory T: usolv(T,C) iff T shows (C) and T &amp; C shows ()</p> <p>The constraint must be solvable by a substitution derivable by massaging the constraint: usolv(F Int ~ Int, F ~ Int) because: (F Int ~ Int &amp; F ~ Int) =/=&gt; ( ~ Int) Similar definition by Sulzmann &amp; Stuckey [TOPLAS2005], also recent related work by Camarao et al. </p> <p>Conclusions and directions16The cost of implicit local generalization is high, we should find alternatives or not generalize implicitly</p> <p>Directions and ongoing work: </p> <p>A full GHC implementation that supports Haskell type classes, GADTs, type functions, and first-class polymorphism [journal submission soon]</p> <p>A declarative specification that deals with ambiguity is open</p> <p>17Thank you for your attention</p>

Recommended

View more >