Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "System F with type equality coercions Simon Peyton Jones (Microsoft) Manuel Chakravarty (University of New South Wales) Martin Sulzmann (University of."— 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 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 HaskellSystem FC/C--/x86 Optimise GHC “core” language

3 Type directed compilation The Haskell gorilla Dozens of data types; hundreds of contructors System F C/C--/x86 Optimise Two data types Ten constructors

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

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

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

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

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

9 The problem with F Polymorphic types, function definitions Algebraic data types, pattern matching, list comprehensions, Type classes Functional dependencies Existential data types GADTs Associated types 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 -> Type doesn’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 In the Zero branch, a=Int In the Pair branch, a=(b,c) But how can we express that in System F? 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]

13 Functional dependencies [Jones ESOP’00] Originally designed to guide inference; fundeps cause extra unifications (“improvement”) to take place Absolutely no impact on intermediate language BUT some nasty cases cannot be translated to F 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... 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 Associated types [POPL’05, ICFP’05] Elem is a type function, mapping the collection type to the associated element 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? 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

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 1.Type-equality coercions : a very well- understood idea in the Types community, but details are interesting. 2.Abstract type constructors and coercion constants : perhaps not so familiar

17 FC in action 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) 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 Result type is always Exp a Type always starts “  a ” Equality constraints express the extra knowledge we can exploit during pattern- matching 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 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 zero : Exp Int zero = Zero Int (refl Int) one : Exp Init one = Succ Int (refl Int) zero

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 (sym g) : Int  a Pattern matching binds a coercion argument Cast ( ►) exploits the coercion to change the type: 0 : Int (0 ► (sym g)) : a eval:: Exp a -> a eval =  a. (x:Exp a). case x of Zero (g:a  Int) -> 0 ► (sym g)...

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

21 Abstract type constructors 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;... type Elem : * -> * data CollectsD c where CD :  c. c -> (Elem c -> c -> c) -> CollectsD c Abstract type constructor: says only “Elem is a type constructor” Class declaration generates a data type declaration as usual

22 Abstract type constructors 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;... 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 Abstract type constructors 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;... type Elem :: * -> * data CollectsD c where CD :  c. c -> (Elem c -> c -> c) -> CollectsD c coercion cBitSet : Elem Bitset  Char dBitSet : CollectsD BitSet dBitSet = CD BitSet (...) (...) foo :: Char -> BitSet foo x = insert x empty foo : Char -> BitSet foo x = insertBitSet dBitSet (x ► (sym cBitSet)) (empty BitSet dBitSet)

24 Abstract type constructors 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;... 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 Only interesting feature Used for coercion and application

28 Types Coercions Ordinary types

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

30 Types Coercions are types Various forms of coercions

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  : (  1 ->  2 ) = (  1 ->  2 )  1 :  1 =  1  2 :  2 =  2 Move a coercion on the lambda to a coercion on its argument and result 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  contains no coercion constants then  is consistent. This is the GADT case. If a set of coercion constants in  form a confluent, terminating rewrite system, then  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


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

Similar presentations


Ads by Google