SLIDE 1 Simon Peyton Jones, Dimitrios Vytiniotis (Microsoft Research) Stephanie Weirich, Brent Yorgey (University of Pennsylvania) Julien Cretin (Inria), Pedro Magalhaes (Utrecht)
October 2011
SLIDE 2
Static typing eradicates whole species of bugs The static type of a function is a partial specification: its says something (but not too much) about what the function does reverse :: [a] -> [a] The spectrum of confidence
Increasingly precise specification Increasing confidence that the program does what you want
SLIDE 3
The static type of a function is like a weak specification: its says something (but not too much) about what the function does reverse :: [a] -> [a] Static typing is by far the most widely-used program verification technology in use today: particularly good cost/benefit ratio
Lightweight (so programmers use them) Machine checked (fully automated, every compilation) Ubiquitous (so programmers can’t avoid them)
SLIDE 4
Static typing eradicates whole species of bugs Static typing is by far the most widely-used program verification technology in use today: particularly good cost/benefit ratio The spectrum of confidence
Increasingly precise specification Increasing confidence that the program does what you want
Hammer (cheap, easy to use, limited effectivenes) Tactical nuclear weapon (expensive, needs a trained user, but very effective indeed)
Types Coq
SLIDE 5
The type system designer seeks to Retain the Joyful Properties of types While also:
making more good programs pass the type checker making fewer bad programs pass the type checker
SLIDE 6
SLIDE 7
‘a’ stands for a type ‘f’ stands for a type constructor data Tree f a = Leaf a | Node (f (Tree f a)) type BinTree a = Tree (,) a type RoseTree a = Tree [] a type AnnTree a = Tree AN a data AN a = AN String a a
SLIDE 8
‘a’ stands for a type ‘f’ stands for a type constructor You can do this in Haskell, but not in ML, Java, .NET etc Kinds: data Tree f a = Leaf a | Node (f (Tree f a)) a :: * f :: * -> * Tree :: (*->*) -> * -> *
* is the kind of types
SLIDE 9
Just as
Types classify terms eg 3 :: Int, (\x.x+1) :: Int -> Int Kinds classify types eg Int :: *, Maybe :: * -> *, Maybe Int :: *
Just as
Types stop you building nonsensical terms eg (True + 4) Kinds stop you building nonsensical types eg (Maybe Maybe)
::= * | ->
a :: * f :: * -> * Tree :: (*->*) -> * -> *
SLIDE 10
Being able to abstract over a higher-kinded ‘m’ is utterly crucial We can give a kind to Monad: Monad :: (*->*) -> Constraint
class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b sequence :: Monad m => [m a] -> m [a] sequence [] = return [] sequence (a:as) = a >>= \x -> sequence as >>= \xs -> return (x:xs)
SLIDE 11
But is this ok too? What kind does T have?
T :: (* -> *) -> * -> *? T :: ((* -> *) -> *) -> (* -> *) -> *?
Haskell 98 “defaults” to the first data T f a = MkT (f a) type T1 = T Maybe Int data F f = MkF (f Int) type T2 = T F Maybe Maybe :: * -> * F :: (*->*) -> *
SLIDE 12
What kind does T have?
T :: (* -> *) -> * -> *? T :: ((* -> *) -> *) -> (* -> *) -> *?
Haskell 98 “defaults” to the first This is Obviously Wrong! We want... data T f a = MkT (f a)
SLIDE 13
What kind does T have?
T :: (* -> *) -> * -> *? T :: ((* -> *) -> *) -> (* -> *) -> *?
Haskell 98 “defaults” to the first This is obviously wrong! We want... data T f a = MkT (f a)
T :: k. (k->*) -> k -> *
Kind polymorphism
SLIDE 14
Syntax of kinds data T f a = MkT (f a)
T :: k. (k->*) -> k -> *
::= * | -> | k. | k
SLIDE 15
And hence: So poly-kinded type constructors mean that terms too must be poly-kinded. data T f a = MkT (f a)
T :: k. (k->*) -> k -> * MkT :: k. (f:k->*) (a:k). f a -> T f a
A kind A type
SLIDE 16
Just as we infer the most general type of a function definition, so we should infer the most general kind of a type definition Just like for functions, the type constructor can be used only monomorphically its own RHS. T2 forces T’s kind to be (*->*) -> * data T f a = MkT (f a) | T2 (T Maybe Int)
SLIDE 17
Haskell today:
class Typeable a where typeOf :: a -> TypeRep instance Typeable Int where typeOf _ = TyCon “Int” instance Typeable a => Typeable (Maybe a) where typeOf _ = TyApp (TyCon “Maybe”) (typeOf (undefined :: a))
SLIDE 18
instance Typeable a => Typeable (Maybe a) where typeOf _ = TyApp (TyCon “Maybe”) (typeOf (undefined :: a)) instance (Typeable f, Typeable a) => Typeable (f a) where typeOf _ = TyApp (typeOf (undefined :: f)) (typeOf (undefined :: a))
No! Yes!
But: Typeable :: * -> Constraint, but f :: *->* (undefined :: f) makes no sense, since f :: *->*
SLIDE 19
Typeable :: k. k -> Constraint Proxy :: k. k -> * Now everything is cool:
class Typeable a where typeOf :: Proxy a -> TypeRep data Proxy a instance (Typeable f, Typeable a) => Typeable (f a) where typeOf _ = TyApp (typeOf (undefined :: Proxy f)) (typeOf (undefined :: Proxy a))
SLIDE 20
Type inference becomes a bit more tricky – but not much.
Instantiate f :: forall k. forall (a:k). tau with a fresh kind unification variable for k, and a fresh type unification variable for a When unifying (a ~ some-type), unify a’s kind with some-type’s kind.
Intermediate language (System F)
Already has type abstraction and application Add kind abstraction and application
SLIDE 21
SLIDE 22
class Collection c where insert :: a -> c a -> c a instance Collection [] where insert x [] = [x] insert x (y:ys) | x==y = y : ys | otherwise = y : insert x ys Does not work! We need Eq!
SLIDE 23 class Collection c where insert :: Eq a => a -> c a -> c a instance Collection [] where insert x [] = [x] insert x (y:ys) | x==y = y : ys | otherwise = y : insert x ys instance Collection BalancedTree where insert = …needs (>)…
This works
BUT THIS DOESN’T
SLIDE 24 We want the constraint to vary with the collection c!
class Collection c where type X c a :: Constraint insert :: X c a => a -> c a -> c a instance Collection [] where type X [] a = Eq a insert x [] = [x] insert x (y:ys) | x==y = y : ys | otherwise = y : insert x ys
An associated type of the class For lists, use Eq
SLIDE 25 We want the constraint to vary with the collection c!
class Collection c where type X c a :: Constraint insert :: X c a => a -> c a -> c a instance Collection BalancedTree where type X BalancedTree a = (Ord a, Hashable a) insert = …(>)…hash…
For balanced trees use (Ord,Hash)
SLIDE 26
Lovely because, it is simply a combination of
Associated types (existing feature) Having Constraint as a kind
No changes at all to the intermediate language!
::= * | -> | k. | k | Constraint
SLIDE 27
SLIDE 28 Hurrah for GADTs What is Zero, Succ? Kind of Vec? Yuk! Nothing to stop you writing stupid types: f :: Vec Int a -> Vec Bool a
data Vec n a where Vnil :: Vec Zero a Vcons :: a -> Vec n a -> Vec (Succ n) a data Zero data Succ a
SLIDE 29 Haskell is a strongly typed language But programming at the type level is entirely un-typed – or rather uni-typed, with one type, *. How embarrassing is that?
data Zero data Succ a
SLIDE 30
Now the type (Vec Int a) is ill-kinded; hurrah Nat is a kind, here introduced by ‘datakind’
datakind Nat = Zero | Succ Nat data Vec n a where Vnil :: Vec Zero a Vcons :: a -> Vec n a -> Vec (Succ n) a
Vec :: Nat -> * -> *
SLIDE 31
Nat is an ordinary type, but it is automatically promoted to be a kind as well Its constuctors are promotd to be (uninhabited) types Mostly: simple, easy data Nat = Zero | Succ Nat data Vec n a where Vnil :: Vec Zero a Vcons :: a -> Vec n a -> Vec (Succ n) a
Vec :: Nat -> * -> *
SLIDE 32
Add :: Nat -> Nat -> Nat
data Nat = Zero | Succ Nat type family Add (a::Nat) (b::Nat) :: Nat type instance Add Z n = n type instance Add (Succ n) m = Succ (Add n m)
SLIDE 33 Where there is only one Foo (type or data constructor) use that If both Foo’s are in scope, “Foo” in a type means the type constructor (backward compat) If both Foo’s are in scope, ‘Foo means the data constructor
data Foo = Foo Int f :: T Foo -> Int
Type constructor Data constructor Which?
SLIDE 34 Which data types are promoted? Keep it simple: only simple, vanilla, types with kinds of form T :: * -> * -> … -> * Avoids the need for
A sort system (to classify kinds!) Kind equalities (for GADTs)
data T where MkT :: a -> (a->Int) -> T data S where MkS :: S Int
Existentials? GADTs?
SLIDE 35
SLIDE 36 Giant source language
contructors, dozens of types
Tiny intermediate language
- 10 constructors, 2 types
- Explicitly typed
- Optimiser preserves
types Core
SLIDE 37
Types Kinds Abstraction and application for... Terms Coercions
SLIDE 38
Take lessons from term :: type and apply them to type :: kind
Polymorphism Constraint kind Data types
Hopefully: no new concepts. Re-use programmers intuitions abou how typing works, one level up. Fits smoothly into the IL Result: world peace