Advanced Type System Features Tom Schrijvers Leuven Haskell User Group
Data Recursion Genericity Schemes Expression Problem Monads GADTs DSLs Type Type Families Classes Lists and Effect Free Other Handlers Theorems Monoids
Data Recursion Genericity Schemes Expression Problem Monads GADTs GADTS DSLs Type Type Families Classes Lists and Effect Free Other Handlers Theorems Monoids
Static Type System
Static Type System Lightweight specifications Verified / enforced by the type checker
Static Type System
Static Type System Rules out many invalid programs
Static Type System Rules out many invalid programs Rules out some valid programs
Advanced Type Systems accept more valid programs accept fewer invalid programs
Advanced Type Systems accept more valid programs Java 5 generics Java 4 accept fewer invalid programs
A Problem with Expressions
Expressions data Exp = ILit Int Add Exp Exp eval :: Exp -> Int eval (ILit n) = n eval (Add e1 e2) = eval e1 + eval e2
More Expressions data Exp = ILit Int Add Exp Exp BLit Bool
Revised Evaluator eval :: Exp -> Int eval (ILit n) = n eval (Add e1 e2) = eval e1 + eval e2 eval (BLit b) = b
Revised Evaluator eval :: Exp -> Int eval (ILit n) = n eval (Add e1 e2) = eval e1 + eval e2 eval (BLit b) = b
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Val eval (ILit n) = n eval (Add e1 e2) = eval e1 + eval e2 eval (BLit b) = b
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Val eval (ILit n) = n eval (Add e1 e2) = eval e1 + eval e2 eval (BLit b) = b
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Val eval (ILit n) = IVal n eval (Add e1 e2) = IVal (eval e1 + eval e2) eval (BLit b) = BVal b
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Val eval (ILit n) = IVal n eval (Add e1 e2) = IVal (eval e1 + eval e2) eval (BLit b) = BVal b
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Val eval (ILit n) = IVal n eval (Add e1 e2) = case (eval e1, eval e2) of (IVal n1, IVal n2) -> IVal (n1+n2) eval (BLit b) = BVal b
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Val eval (ILit n) = IVal n eval (Add e1 e2) = case (eval e1, eval e2) of (IVal n1, IVal n2) -> IVal (n1+n2) _ ->??? eval (BLit b) = BVal b
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Maybe Val eval (ILit n) = IVal n eval (Add e1 e2) = case (eval e1, eval e2) of (IVal n1, IVal n2) -> IVal (n1+n2) _ -> Nothing eval (BLit b) = BVal b
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Maybe Val eval (ILit n) = IVal n eval (Add e1 e2) = case (eval e1, eval e2) of (IVal n1, IVal n2) -> IVal (n1+n2) _ -> Nothing eval (BLit b) = BVal b
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Maybe Val eval (ILit n) = Just (IVal n) eval (Add e1 e2) = case (eval e1, eval e2) of (IVal n1, IVal n2) -> Just (IVal (n1+n2)) _ -> Nothing eval (BLit b) = Just (BVal b)
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Maybe Val eval (ILit n) = Just (IVal n) eval (Add e1 e2) = case (eval e1, eval e2) of (IVal n1, IVal n2) -> Just (IVal (n1+n2)) _ -> Nothing eval (BLit b) = Just (BVal b)
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Maybe Val eval (ILit n) = Just (IVal n) eval (Add e1 e2) = case (eval e1, eval e2) of (Just (IVal n1), Just (IVal n2)) -> Just (IVal (n1+n2)) _ -> Nothing eval (BLit b) = Just (BVal b)
Revised Evaluator data Val = IVal Int BVal Bool eval :: Exp -> Maybe Val eval (ILit n) = Just (IVal n) eval (Add e1 e2) Overhead due to possibly ill-typed expressions = case (eval e1, eval e2) of (Just (IVal n1), Just (IVal n2)) -> Just (IVal (n1+n2)) _ -> Nothing eval (BLit b) = Just (BVal b)
GADTs to the Rescue
The Problem admits invalid values Exp
The Problem admits invalid values Exp Add (BLit True) (ILit 5)
The Problem accept more valid programs admits invalid values Exp accept fewer invalid programs
The Problem accept more valid programs admits invalid values Exp GADTs accept fewer invalid programs
The Problem accept more valid programs admits invalid values Exp Exp a GADTs accept fewer invalid programs
The Problem accept more valid programs admits invalid values Exp admits only valid values Exp a GADTs accept fewer invalid programs
Parametrised Expressions Exp a
Parametrised Expressions Expressions that yield a value of type a type a Exp a
Parametrised Expressions Expressions that yield a value of type a type a Exp a indexed family index
Parametrised Expressions Expressions that yield a value of type a type a Exp a indexed family index family members Exp Int Exp Bool
Parametrised Expressions Expressions that yield a value of type a type a Exp a indexed family index family members Exp Int Exp Bool ILit 0 Add (ILit 1) (ILit 2)
Parametrised Expressions Expressions that yield a value of type a type a Exp a indexed family index family members Exp Int ILit 0 Exp Bool BLit True Add (ILit 1) (ILit 2) BLit False
Generalized Algebraic Data Type data Exp where ILit :: Int -> Exp Add :: Exp -> Exp -> Exp BLit :: Bool -> Exp
Generalized Algebraic Data Type data Exp a where ILit :: Int -> Exp Int Add :: Exp Int -> Exp Int -> Exp Int BLit :: Bool -> Exp Bool
Generalized Algebraic Data Type indexed family data Exp a where ILit :: Int -> Exp Int Add :: Exp Int -> Exp Int -> Exp Int BLit :: Bool -> Exp Bool
Generalized Algebraic Data Type indexed family Refined index data Exp a where ILit :: Int -> Exp Int Add :: Exp Int -> Exp Int -> Exp Int BLit :: Bool -> Exp Bool
GADT Evaluator eval :: Exp a -> a eval (ILit n) = n eval (Add e1 e2) = eval e1 + eval e2 eval (BLit b) = b
GADT Evaluator eval :: Exp a -> a No noise due to possibly ill-typed expressions! eval (ILit n) = n eval (Add e1 e2) = eval e1 + eval e2 eval (BLit b) = b
GADT Evaluator eval :: Exp a -> a No noise due to possibly ill-typed expressions! eval (ILit n) = n From the pattern match we know that a = Int eval (Add e1 e2) = eval e1 + eval e2 eval (BLit b) = b
GADT Evaluator eval :: Exp a -> a No noise due to possibly ill-typed expressions! eval (ILit n) = n From the pattern match we know that a = Int eval (Add e1 e2) = eval e1 + eval e2 eval (BLit b) = b From the pattern match we know that a = Bool
GADT Extension data Exp a where ILit :: Int -> Exp Int Add :: Exp Int -> Exp Int -> Exp Int BLit :: Bool -> Exp Bool IfThenElse :: Exp Bool -> Exp a -> Exp a -> Exp a
Extended GADT Evaluator eval :: Exp a -> a eval (ILit n) = n eval (Add e1 e2) = eval e1 + eval e2 eval (BLit b) = b eval (IfThenElse i t e) = if eval i then eval t else eval e
Alternative Syntax data Exp = ILit Int Add (Exp ) (Exp ) BLit Bool
Alternative Syntax data Exp a = a ~ Int => ILit Int a ~ Int => Add (Exp Int) (Exp Int) a ~ Bool => BLit Bool
Alternative Syntax data Exp a = a ~ Int => ILit Int a ~ Int => Add (Exp Int) (Exp Int) a ~ Bool => BLit Bool Equality Constraint
Alternative Syntax data Exp a = a ~ Int => ILit Int a ~ Int => Add (Exp Int) (Exp Int) a ~ Bool => BLit Bool Equality Constraint a ~ Int a equals Int
Ensure & Assume Construct value ILit n :: Exp a Type checker has to assure that a ~ Int
Ensure & Assume Construct value ILit n :: Exp a Type checker has to assure that a ~ Int Deconstruct value case e :: Exp a of ILit n -> body Type checker can assume that a ~ Int
Length-Indexed Lists with GADTs
Regular Lists data List a = Nil Cons a (List a) head :: List a -> a head (Cons x xs) = x
Regular Lists data List a = Nil Cons a (List a) head :: List a -> a head (Cons x xs) = x
Regular Lists data List a = Nil Cons a (List a) head :: List a -> a head (Cons x xs) = x crashes on empty list!
The Problem crashes on empty list head List a
The Problem crashes on empty list head List a head Nil
The Problem accept more valid programs crashes on empty list head List a accept fewer invalid programs
The Problem accept more valid programs crashes on empty list head List a GADTs accept fewer invalid programs
The Problem accept more valid programs crashes on empty list head List a head List n a GADTs accept fewer invalid programs
The Problem accept more valid programs crashes on empty list head List a does not accept head Nil head List n a GADTs accept fewer invalid programs
Length-Indexed Lists List n a
Length-Indexed Lists List n a indexed family index
Length-Indexed Lists List n a indexed family index family members List Z a List (S Z) a List (S (S Z)) a
Length-Indexed Lists List n a indexed family index family members List Z a List (S Z) a List (S (S Z)) a Nil Cons x Nil Cons x (Cons y)ni
Length-Index List GADT data List a where Nil :: List a Cons :: a -> List a -> List a
Length-Index List GADT data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a
Length-Index List GADT indexed family data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a
Length-Index List GADT indexed family Refined index data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a
Length-Index List GADT indexed family Refined index data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a data Z data S n Empty data types: only used as type indices
Safe Head data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a head :: List a -> a head (Cons x xs) = x
Safe Head data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a head :: List (S n) a -> a head (Cons x xs) = x
Safe Head data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a head :: List (S n) a -> a head (Cons x xs) = x > head Nil Couldn't match type Z with S n0 Expected type: List (S n0) a Actual type: List Z a In the first argument of head, namely Nil In the expression: head Nil
Safe Zip data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a zip :: List a -> List b -> List (a,b) zip Nil Nil = Nil zip (Cons x xs) (Cons y ys) = Cons (x,y) (zip xs ys) lists of different length!
Safe Zip data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a zip :: List n a -> List n b -> List n (a,b) zip Nil Nil = Nil zip (Cons x xs) (Cons y ys) = Cons (x,y) (zip xs ys)
Type Families
Append? data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a append :: List n a -> List m a -> List? a append Nil ys = ys append (Cons x xs) ys = Cons x (append xs ys)
Append? data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a append :: List n a -> List m a -> List? a append Nil ys n + m = ys append (Cons x xs) ys = Cons x (append xs ys)
Append? data List n a where Nil :: List Z a Cons :: a -> List n a -> List (S n) a append :: List n a -> List m a -> List? a append Nil ys n + m = ys append (Cons x xs) ys = Cons x (append xs ys) type-level computation
The Problem append
The Problem accept more valid programs append accept fewer invalid programs
The Problem accept more valid programs Type Families append accept fewer invalid programs
The Problem accept more valid programs append Type Families append accept fewer invalid programs
Type Family aka Type Function type family Add n m where Add Z m = m Add (S n) m = S (Add n m)
Append with Type Family type family Add n m where Add Z m = m Add (S n) m = S (Add n m) append :: List n a -> List m a -> List (Add n m) a append Nil ys = ys append (Cons x xs) ys = Cons x (append xs ys)
Open & Associated Type Families
Collect Type Class class Collect c where insert :: c ->? -> c
Elem Type Family (open) type class declaration class Collect c where insert :: c -> Elem c -> c type family Elem c open type family declaration
Instances type class instance instance Collect [e] where insert l c = c : l type instance Elem [e] = e type family instance
Open Nature type instance Elem [e] = e instance Collect [e] where insert l c = c : l type instance Elem ByteString = Word8 instance Collect ByteString where insert l c = cons c l
Open Nature type instance Elem [e] = e instance Collect [e] where insert l c = c : l type instance Elem ByteString = Word8 instance Collect ByteString where insert l c = cons c l double instances
Associated Type Family class Collect c where type Elem c insert :: c -> Elem c -> c instance Collect [e] where type Elem [e] = e insert l c = c : l instance Collect ByteString where type Elem ByteString = Word8 insert l c = cons c l
Associated Type Family class Collect c where type Elem c insert :: c -> Elem c -> c instance Collect [e] where type Elem [e] = e insert l c = c : l instance Collect ByteString where type Elem ByteString = Word8 insert l c = cons c l
Summary
Advanced Type System Features Generalised Algebraic Data Types Type-level Functions aka Type Families
Advanced Type System Features Generalised Algebraic Data Types Type-level Functions aka Type Families accept more valid programs accept fewer invalid programs
More To Learn Existential Types Rank-n Polymorphism Kinds: Type Promotion, Kind Polymorphism Type Classes: Functional Dependencies, Resolution Extensions Value-Dependent Types (beyond Haskell)
Next time: 19/5/2015
Data Recursion Genericity Schemes Expression Problem Monads GADTs DSLs Type Type Families Classes Lists and Effect Free other Handlers Theorems Monoids
Data Recursion Genericity Schemes Expression Problem Monads GADTs DSLs Type Type Families Classes Lists Quattro Stagioni Effect Free Handlers Theorems other of Haskell Monoids and
Join the Google Group Leuven Haskell User Group