Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Haskell's Kind System - A Primer

Haskell's Kind System - A Primer

A primer on Type Level programming. My Presentation of the excellent article at https://diogocastro.com/blog/2018/10/17/haskells-kind-system-a-primer/

Tommaso Piazza

November 01, 2018
Tweet

More Decks by Tommaso Piazza

Other Decks in Programming

Transcript

  1. Types We all have seen types & values before ©

    Tommaso Piazza, 2018 - https://github.com/blender 2
  2. Types We all have seen types & values before —

    :t True © Tommaso Piazza, 2018 - https://github.com/blender 2
  3. Types We all have seen types & values before —

    :t True — Bool ✅ © Tommaso Piazza, 2018 - https://github.com/blender 2
  4. Types We all have seen types & values before —

    :t True — Bool ✅ — :t "Hello" © Tommaso Piazza, 2018 - https://github.com/blender 2
  5. Types We all have seen types & values before —

    :t True — Bool ✅ — :t "Hello" — String ✅ © Tommaso Piazza, 2018 - https://github.com/blender 2
  6. Types We all have seen types & values before —

    :t True — Bool ✅ — :t "Hello" — String ✅ — :t (+) © Tommaso Piazza, 2018 - https://github.com/blender 2
  7. Types We all have seen types & values before —

    :t True — Bool ✅ — :t "Hello" — String ✅ — :t (+) — Num a => a -> a -> a ✅ © Tommaso Piazza, 2018 - https://github.com/blender 2
  8. Kinds are to types as types are to values ©

    Tommaso Piazza, 2018 - https://github.com/blender 3
  9. Kinds are to types as types are to values All

    inhabited types have kind * © Tommaso Piazza, 2018 - https://github.com/blender 4
  10. Kinds are to types as types are to values All

    inhabited types have kind * — :k Bool © Tommaso Piazza, 2018 - https://github.com/blender 4
  11. Kinds are to types as types are to values All

    inhabited types have kind * — :k Bool — * © Tommaso Piazza, 2018 - https://github.com/blender 4
  12. Kinds are to types as types are to values All

    inhabited types have kind * — :k Bool — * — :k String © Tommaso Piazza, 2018 - https://github.com/blender 4
  13. Kinds are to types as types are to values All

    inhabited types have kind * — :k Bool — * — :k String — * © Tommaso Piazza, 2018 - https://github.com/blender 4
  14. Kinds are to types as types are to values All

    inhabited types have kind * — :k Bool — * — :k String — * — :k [Int] © Tommaso Piazza, 2018 - https://github.com/blender 4
  15. Kinds are to types as types are to values All

    inhabited types have kind * — :k Bool — * — :k String — * — :k [Int] — * © Tommaso Piazza, 2018 - https://github.com/blender 4
  16. Not all types are inhabited — Just 1 :: Maybe

    © Tommaso Piazza, 2018 - https://github.com/blender 5
  17. Not all types are inhabited — Just 1 :: Maybe

    — ❌ Expecting one more argument to ‘Maybe’ © Tommaso Piazza, 2018 - https://github.com/blender 5
  18. Not all types are inhabited — Just 1 :: Maybe

    — ❌ Expecting one more argument to ‘Maybe’ — Right 1 :: Either © Tommaso Piazza, 2018 - https://github.com/blender 5
  19. Not all types are inhabited — Just 1 :: Maybe

    — ❌ Expecting one more argument to ‘Maybe’ — Right 1 :: Either — ❌ Expecting two more arguments to ‘Either’ © Tommaso Piazza, 2018 - https://github.com/blender 5
  20. Not all types are inhabited — Just 1 :: Maybe

    — ❌ Expecting one more argument to ‘Maybe’ — Right 1 :: Either — ❌ Expecting two more arguments to ‘Either’ — What are Either and Maybe ? © Tommaso Piazza, 2018 - https://github.com/blender 5
  21. Constructors Let's talk about Data Constructors data Person = MkPerson

    { name :: String, age :: Int } deriving Show © Tommaso Piazza, 2018 - https://github.com/blender 6
  22. Constructors Let's talk about Data Constructors data Person = MkPerson

    { name :: String, age :: Int } deriving Show — 2 Arguments © Tommaso Piazza, 2018 - https://github.com/blender 6
  23. Constructors Let's talk about Data Constructors data Person = MkPerson

    { name :: String, age :: Int } deriving Show — 2 Arguments — MkPerson :: String -> Int -> Person © Tommaso Piazza, 2018 - https://github.com/blender 6
  24. Constructors Let's talk about Data Constructors data Person = MkPerson

    { name :: String, age :: Int } deriving Show — 2 Arguments — MkPerson :: String -> Int -> Person — :t MKPerson "Tommaso" © Tommaso Piazza, 2018 - https://github.com/blender 6
  25. Constructors Let's talk about Data Constructors data Person = MkPerson

    { name :: String, age :: Int } deriving Show — 2 Arguments — MkPerson :: String -> Int -> Person — :t MKPerson "Tommaso" — MKPerson "Tommaso" :: Int -> Person © Tommaso Piazza, 2018 - https://github.com/blender 6
  26. Constructors (2) Type Constrcutors data Either a b = Left

    a | Right b -- *_____▾_____* -- Type Constructor © Tommaso Piazza, 2018 - https://github.com/blender 7
  27. Constructors (2) Type Constrcutors data Either a b = Left

    a | Right b -- *_____▾_____* -- Type Constructor — :k Either String Int © Tommaso Piazza, 2018 - https://github.com/blender 7
  28. Constructors (2) Type Constrcutors data Either a b = Left

    a | Right b -- *_____▾_____* -- Type Constructor — :k Either String Int — * © Tommaso Piazza, 2018 - https://github.com/blender 7
  29. Constructors (2) Type Constrcutors data Either a b = Left

    a | Right b -- *_____▾_____* -- Type Constructor — :k Either String Int — * — :k Either String © Tommaso Piazza, 2018 - https://github.com/blender 7
  30. Constructors (2) Type Constrcutors data Either a b = Left

    a | Right b -- *_____▾_____* -- Type Constructor — :k Either String Int — * — :k Either String — * -> * © Tommaso Piazza, 2018 - https://github.com/blender 7
  31. Constructors (2) Type Constrcutors data Either a b = Left

    a | Right b -- *_____▾_____* -- Type Constructor — :k Either String Int — * — :k Either String — * -> * — :k Either © Tommaso Piazza, 2018 - https://github.com/blender 7
  32. Constructors (2) Type Constrcutors data Either a b = Left

    a | Right b -- *_____▾_____* -- Type Constructor — :k Either String Int — * — :k Either String — * -> * — :k Either — * -> * © Tommaso Piazza, 2018 - https://github.com/blender 7
  33. Kind Signatures Just as you can write type signatures y

    :: String -> IO () y = putStrLn You can write kind signatures data List a = Cons a (List a) | Nil {-# LANGUAGE KindSignatures #-} data List (a :: *) = Cons a (List a) | Nil © Tommaso Piazza, 2018 - https://github.com/blender 8
  34. HOFs Higher order functions take functions are paramters map ::

    (a -> b) -> [a] -> [b] © Tommaso Piazza, 2018 - https://github.com/blender 9
  35. HKTs Higher kinded types take type constuctors of kind *

    -> * as parameters {-# LANGUAGE KindSignatures #-} data NonEmpty (f :: * -> *) (a :: *) = MkNonEmpty { head :: a, tail :: f a } type NonEmptyList = NonEmpty [] let nonEmptyListOfInts = MkNonEmpty 1 [] :: NonEmptyList Int © Tommaso Piazza, 2018 - https://github.com/blender 10
  36. Not everything is a ⭐ — :k Show © Tommaso

    Piazza, 2018 - https://github.com/blender 11
  37. Not everything is a ⭐ — :k Show — Show

    :: * -> Constraint © Tommaso Piazza, 2018 - https://github.com/blender 11
  38. Not everything is a ⭐ — :k Show — Show

    :: * -> Constraint — :k Functor © Tommaso Piazza, 2018 - https://github.com/blender 11
  39. Not everything is a ⭐ — :k Show — Show

    :: * -> Constraint — :k Functor — Functor :: (* -> *) -> Constraint © Tommaso Piazza, 2018 - https://github.com/blender 11
  40. Not everything is a ⭐ — :k Show — Show

    :: * -> Constraint — :k Functor — Functor :: (* -> *) -> Constraint — EverythingOnThisSide m => m IsAConstraint © Tommaso Piazza, 2018 - https://github.com/blender 11
  41. Constraints ! Use the Constraint kind by enabling {-# LANGUAGE

    ConstraintKinds #-} © Tommaso Piazza, 2018 - https://github.com/blender 12
  42. Using Constraints Data.Set has no Functor instance class Functor (f

    :: * -> *) where fmap :: (a -> b) -> f a -> f b Data.Set.map :: Ord b => (a -> b) -> Set a -> Set b -- *___ ▾ ___* -- ! © Tommaso Piazza, 2018 - https://github.com/blender 13
  43. Police Data.Set.map :: Ord b => (a -> b) ->

    Set a -> Set b -- *___ ▾ ___* * ▾ * * ▾ * -- ! f f © Tommaso Piazza, 2018 - https://github.com/blender 14
  44. Police Data.Set.map :: Ord b => (a -> b) ->

    Set a -> Set b -- *___ ▾ ___* * ▾ * * ▾ * -- ! f f class GFunctor ! (f :: * -> *) where fmap :: ! b => (a -> b) -> f a -> f b © Tommaso Piazza, 2018 - https://github.com/blender 15
  45. Police Data.Set.map :: Ord b => (a -> b) ->

    Set a -> Set b -- *___ ▾ ___* * ▾ * * ▾ * -- ! f f class GFunctor ! (f :: * -> *) where fmap :: ! b => (a -> b) -> f a -> f b class GFunctor (c :: * -> Constraint) (f :: * -> *) | f -> c where gfmap :: c b => (a -> b) -> (f a -> f b) © Tommaso Piazza, 2018 - https://github.com/blender 16
  46. !"# {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE KindSignatures #-} {-#

    LANGUAGE FunctionalDependencies #-} import Data.Kind (Constraint) import qualified Data.Set as Set import qualified Data.List as List class GFunctor (c :: * -> Constraint) (f :: * -> *) | f -> c where gfmap :: c b => (a -> b) -> (f a -> f b) instance GFunctor Ord Set.Set where gfmap = Set.map © Tommaso Piazza, 2018 - https://github.com/blender 17
  47. No ! no problem {-# LANGUAGE FlexibleInstances #-} class EmptyConstraint

    a instance EmptyConstraint a © Tommaso Piazza, 2018 - https://github.com/blender 18
  48. No ! no problem {-# LANGUAGE FlexibleInstances #-} class EmptyConstraint

    a instance EmptyConstraint a instance GFunctor EmptyConstraint [] where gfmap = List.map © Tommaso Piazza, 2018 - https://github.com/blender 19
  49. Promotions A data type like data ConnectionStatus = Open |

    Closed © Tommaso Piazza, 2018 - https://github.com/blender 20
  50. Promotions A data type like data ConnectionStatus = Open |

    Closed Can be promoted to a kind {-# LANGUAGE DataKinds #-} data ConnectionStatus = Open | Closed © Tommaso Piazza, 2018 - https://github.com/blender 21
  51. DataKinds {-# LANGUAGE DataKinds #-} Creates a kind ConnectionStatus and

    two types 'Open and 'Closed © Tommaso Piazza, 2018 - https://github.com/blender 23
  52. DataKinds {-# LANGUAGE DataKinds #-} Creates a kind ConnectionStatus and

    two types 'Open and 'Closed — :t Open © Tommaso Piazza, 2018 - https://github.com/blender 23
  53. DataKinds {-# LANGUAGE DataKinds #-} Creates a kind ConnectionStatus and

    two types 'Open and 'Closed — :t Open — Open :: ConnectionStatus © Tommaso Piazza, 2018 - https://github.com/blender 23
  54. DataKinds {-# LANGUAGE DataKinds #-} Creates a kind ConnectionStatus and

    two types 'Open and 'Closed — :t Open — Open :: ConnectionStatus — :k Open (or :k 'Open ) © Tommaso Piazza, 2018 - https://github.com/blender 23
  55. DataKinds {-# LANGUAGE DataKinds #-} Creates a kind ConnectionStatus and

    two types 'Open and 'Closed — :t Open — Open :: ConnectionStatus — :k Open (or :k 'Open ) — Open :: ConnectionStatus © Tommaso Piazza, 2018 - https://github.com/blender 23
  56. Type level connections data Connection (s :: ConnectionStatus) = MkConnection

    { connectionId :: String } open :: IO (Connection Open) open = return $ MkConnection "someId" close :: Connection Open -> IO (Connection Closed) close (MkConnection c) = return $ MkConnection (c ++ " is now closed") © Tommaso Piazza, 2018 - https://github.com/blender 24
  57. Strings as types Kind Symbol fro GHC.TypeList newtype Money (currency

    :: Symbol) = Money Rational fivePence :: Money "GBP" fivePence = Money (5 % 100) © Tommaso Piazza, 2018 - https://github.com/blender 25
  58. Strings as types Kind Symbol newtype Money (currency :: Symbol)

    = Money Rational fivePence :: Money "GBP" fivePence = Money (5 % 100) twoEuros :: Money "EUR" twoEuros = Money 2 add :: Money c -> Money c -> Money c add (Money x) (Money y) = Money (x + y) add fivePence fivePence Money (1 % 10) add fivePence twoEuros <interactive>:8:15: error: • Couldn't match type ‘"EUR"’ with ‘"GBP"’ © Tommaso Piazza, 2018 - https://github.com/blender 26
  59. 1,2,3... as types Kind Nat {-# LANGUAGE KindSignatures, DataKinds #-}

    import GHC.TypeLits (Symbol, Nat) newtype Discrete (currency :: Symbol) (scale :: (Nat, Nat)) = Discrete Integer oneDollar :: Discrete "USD" '(1, 1) oneDollar = Discrete 1 oneDollarThirtyCents :: Discrete "USD" '(100, 1) oneDollarThirtyCents = Discrete 130 © Tommaso Piazza, 2018 - https://github.com/blender 27
  60. I need help! https://github.com/blender/Rome — Writte in Haskell — Used

    by Mozilla and others — Tons of room for improvement © Tommaso Piazza, 2018 - https://github.com/blender 29