1 / 41

System F with type equality coercions

System F with type equality coercions. Simon Peyton Jones (Microsoft) Manuel Chakravarty (University of New South Wales) Martin Sulzmann (University of Singapore). Type directed compilation. GHC “core” language. GHC compiles Haskell to a typed intermediate language: System F

zeheb
Download Presentation

System F with type equality coercions

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. System F with type equality coercions Simon Peyton Jones (Microsoft) Manuel Chakravarty (University of New South Wales) Martin Sulzmann (University of Singapore)

  2. Type directed compilation GHC “core” language • GHC compiles Haskell to a typed intermediate language: System F • Two big advantages • Some transformations are guided by types • Type-checking Core is a strong check on correctness of transformations Haskell System F C/C--/x86 Optimise

  3. Type directed compilation The Haskellgorilla Dozens ofdata types;hundreds ofcontructors Optimise C/C--/x86 System F Two data typesTen constructors

  4. System F: the mighty midget Polymorphic types, function definitions System F

  5. System F: the mighty midget Algebraic data types, pattern matching, list comprehensions, Polymorphic types, function definitions System F + data types

  6. System F: the mighty midget Functional dependencies Type classes Algebraic data types, pattern matching, list comprehensions, Polymorphic types, function definitions System F + data types

  7. System F: the mighty midget data T = forall a. MkT a (a →Int) Example of use: case x of MkT v f → f v Type of MkT is MkT :: a. a → (a →Int) → T Existential data types Functional dependencies Type classes Algebraic data types, pattern matching, list comprehensions, Polymorphic types, function definitions System F + (existential) data types

  8. System F: the fatter midget GADTs Existential data types Functional dependencies Type classes Algebraic data types, pattern matching, list comprehensions, Polymorphic types, function definitions System F + GADTs

  9. The problem with F Associated types GADTs Existential data types Functional dependencies Type classes Algebraic data types, pattern matching, list comprehensions, Polymorphic types, function definitions SPLAT

  10. A practical problem • GHC uses System F + (existential data types) as its intermediate language • GADTs are already a Big Thing to add to a typed intermediate language • Practical problem: exprType :: Expr -> Typedoesn’t have a unique answer any more • Associated types are simply a bridge too far What to do?

  11. What bits don’t “fit”? • The stuff that doesn’t “fit” is the stuff that involves non-syntactic type equality • Functional dependencies • GADTs • Associated types

  12. GADTs data Exp a where Zero :: Exp Int Succ :: Exp Int -> Exp Int Pair :: Exp b -> Exp c -> Exp (b, c) eval :: Exp a -> a eval Zero = 0 eval (Succ e) = eval e + 1 eval (Pair x y) = (eval x, eval y) Also known as “Inductive type families” and “Guarded recursive data types” [Xi POPL’03] • In the Zero branch, a=Int • In the Pair branch, a=(b,c) • But how can we express that in System F?

  13. Functionaldependencies[Jones ESOP’00] class Collects c e | c->e where empty :: c insert :: e -> c -> c instance Eq e => Collects [e] e where ... instance Collects BitSet Char where ... • Originally designedto guide inference;fundeps causeextra unifications (“improvement”) to take place • Absolutely no impact on intermediate language • BUT some nasty cases cannot be translated to F class Wuggle c where nasty :: (Collects c e) => c -> e -> c instance Wuggle BitSet where ...Argh!... nasty :: forall e. Collects BitSet e => c->e->e Can only be Char

  14. Associatedtypes [POPL’05, ICFP’05] class Collects c where type Elem c empty :: c insert :: Elem c -> c -> c instance Eq e => Collects [e] where type Elem [e] = e; ... instance Collects BitSet where type Elem BitSet= Char; ... foo :: Char -> BitSet foo x = insert x empty • Elem is a typefunction, mappingthe collection typeto the associatedelement type • The original AT papers gave a translation into F by adding type parameters (a la fundep solution) • But that is (a) deeply, disgustingly awkward, and (b) suffers from similar nasty cases as fundeps • Can we support ATs more directly?

  15. The happy answer: FC FC extends System F in a way that... • ... is much more modest than adding GADTs • ...supports GADTs • ...and ATs • ...and the nasty cases of fundeps • ...and perhaps other things besides

  16. Two ingredients • Type-equality coercions: a very well-understood idea in the Types community, but details are interesting. • Abstract type constructors and coercion constants: perhaps not so familiar

  17. data Exp a where Zero :: Exp Int Succ :: Exp Int -> Exp Int Pair :: Exp b -> Exp c -> Exp (b, c) eval :: Exp a -> a eval Zero = 0 eval (Succ e) = eval e + 1 eval (Pair x y) = (eval x, eval y) FC in action data Exp a where Zero : a.(a Int) => Exp a Succ : a.(a Int) => Exp Int -> Exp a Pair : a. bc.(a (b,c)) => Exp b -> Exp c -> Exp a Equality constraints express the extra knowledge we can exploit during pattern-matching Result type is always Exp a Type always starts “a” • This part is very standard • Some authors use this presentation for the source language (Sheard, Xi, Sulzmann)

  18. FC in action data Exp a where Zero :: a.(a Int) => Exp a Succ :: a.(a Int) => Exp Int -> Exp a Pair :: a. bc.(a (b,c)) => Exp b -> Exp c -> Exp a zero : Exp Int zero = Zero Int (refl Int) one : Exp Init one = Succ Int (refl Int) zero Ordinary value argument Ordinary type argument A coercion argument: “evidence” that Int Int (refl Int) : Int Int • We are passing equality evidence around: again, a very standard idea

  19. FC in action data Exp a where Zero :: a.(a Int) => Exp a Succ :: a.(a Int) => Exp Int -> Exp a Pair :: a. bc.(a (b,c)) => Exp b -> Exp c -> Exp a eval:: Exp a -> a eval = a.(x:Exp a). case x of Zero (g:aInt) -> 0 ► (sym g) ... (sym g) : Int a Pattern matching binds a coercion argument Cast (►)exploits the coercion to change the type: 0 : Int (0 ► (sym g)) : a

  20. Coercions are types! A coercion is a type, not a term.e.g. refl Int : Int  Int(refl Int) is a typewhose kind is (Int  Int) Reasons: • Type erasure erases coercions • Terms would allow bogus coercions (letrec g = g in g) : Int  BoolThe type language is strongly normalising; no letrec Weird! A type has a kind, which mentions types...!

  21. class Collects c where type Elem c empty :: c insert :: Elem c -> c -> c instance Collects BitSet where type Elem BitSet = Char; ... instance Eq e => Collects [e] where type Elem [e] = e; ... Abstract type constructors Abstract type constructor: says only “Elem is a type constructor” type Elem : * -> * data CollectsD c where CD : c. c -> (Elem c -> c -> c) -> CollectsD c Class declaration generates a data type declaration as usual

  22. class Collects c where type Elem c empty :: c insert :: Elem c -> c -> c instance Collects BitSet where type Elem BitSet = Char; ... instance Eq e => Collects [e] where type Elem [e] = e; ... Abstract type constructors type Elem :: * -> * data CollectsD c where CD : c. c -> (Elem c -> c -> c) -> CollectsD c Instance decl generates a top-level coercion constant, witnessing that Elem Bitset = Char coercion cBitSet : Elem Bitset  Char dBitSet : CollectsD BitSet dBitSet = CD BitSet (...) (...)

  23. class Collects c where type Elem c empty :: c insert :: Elem c -> c -> c instance Collects BitSet where type Elem BitSet = Char; ... instance Eq e => Collects [e] where type Elem [e] = e; ... Abstract type constructors type Elem :: * -> * data CollectsD c where CD : c. c -> (Elem c -> c -> c) -> CollectsD c foo :: Char -> BitSet foo x = insert x empty coercion cBitSet : Elem Bitset  Char dBitSet : CollectsD BitSet dBitSet = CD BitSet (...) (...) foo : Char -> BitSet foo x = insert BitSet dBitSet (x ►(sym cBitSet)) (empty BitSet dBitSet)

  24. class Collects c where type Elem c empty :: c insert :: Elem c -> c -> c instance Collects BitSet where type Elem BitSet = Char; ... instance Eq e => Collects [e] where type Elem [e] = e; ... Abstract type constructors type Elem :: * -> * data CollectsD c where CD : c. c -> (Elem c -> c -> c) -> CollectsD c A type-parameterised coercion constant coercion cList : (e:*). Elem [e]  e dList : e. CollectsD e -> CollectsD [e] dList = ... ...and a type- and value-parameterised dictionary function

  25. A worry • What is to stop us saying this? • Result: seg-fault city • Answer: the top-level coercion constants must be consistent coercion utterlyBogus : Int  Bool

  26. Some technical details

  27. Terms: utterly unremarkable Used for coercion and application Only interesting feature

  28. Coercions Types Ordinary types

  29. Types Abstract types (must be saturated) Data types Full blown type application

  30. Types Various forms of coercions Coercions are types

  31. Unsurprising coercions

  32. Slightly more surprising • If I know (Tree a  Tree b) then I know that (a  b) • Absolutely necessary to translate Haskell programs with GADTs • Only true for injective type constructors • Not true (in general) for abstract type constructors • That’s why applications of abstract type constructors must be saturated

  33. Consistency • This says that if a coercion relates two data types then they must be identical • This condition is both necessary and sufficient for soundness of FC (proof in paper)

  34. Operational semantics • Largely standard (good) but with some interesting wrinkles A “cvalue” is a plain value possibly wrapped in a cast Coercions are never evaluated at all

  35. Standard rules...

  36. Not so standard Combine the coercions

  37. Not so standard Move a coercion on the lambda to a coercion on its argument and result  : (1 -> 2) = (u1 -> u2) 1 : u1 = 1 2 : 2 = u2 Evaluation carries out proof maintenance Proof terms get bigger and bigger; but can be simplified: sym (sym g) = g sym (refl t) = refl t etc

  38. Results: FC itself • FC is sound: well-typed FC programs do not go wrong • Type erasure does not change the operational behaviour

  39. Results: consistency • Consistency is a bit like confluence; in general, it’s difficult to prove for a particular program, but whole sub-classes of programs may be consistent by construction • If G contains no coercion constants then G is consistent. This is the GADT case. • If a set of coercion constants in G form a confluent, terminating rewrite system, then G is consistent. This is the AT case.

  40. Translating into FC • The translation of both GADTs and ATs is almost embarrassingly simple • During type inference, any use of equality constraints must be expressed as a coercion in the corresponding FC program

  41. Conclusions • Feels “right” • Next: implement FC in GHC • Implications for the source language? • Type equalities have the same flavour as sharing constraints in ML modules. Discuss. (e.g. could ML modules be translated into FC?) Paper Apr 2006 (not yet rejected by ICFP’06) http://research.microsoft.com/~simonpj

More Related