Save 37% off PRO during our Black Friday Sale! »

Free Functors & Monads

Free Functors & Monads

IO in Haskell (or GHC, more specifically), is deeply magical. A function returning IO a can perform any effect, and a caller does not know what is going on: Just printing something to the terminal, calling a web service or launching the missiles. But it doesn't have to be that way: Using free monads, we can construct tiny subsets of IO functionality, combine them together and even pick the concrete interpreter depending on the environment.

Based on the "Functional Mocking" talk from Lambda Days 2015, with more focus on free structures.

Demo code: https://gist.github.com/larsrh/5cd5652c25ec84b8852c

A1216674d5c9747bcdcc716872439137?s=128

Lars Hupel

March 16, 2015
Tweet

Transcript

  1. Free Functors & Monads Lars Hupel March 16th, 2015

  2. A Simple Calculator data Expr = Literal Int | Var

    String | Sum Expr Expr evaluate :: Map String Int -> Expr -> Maybe Int 2 / 22
  3. None
  4. Calculator Revisited data Expr a t = Literal a |

    Var t | Sum (Expr a t) (Expr a t) 4 / 22
  5. Calculator Revisited data Expr a t = Literal a |

    Var t | Sum (Expr a t) (Expr a t) > :t Sum Sum :: Expr a t -> Expr a t -> Expr a t 4 / 22
  6. Calculator Revisited data Expr a t where Literal :: a

    -> Expr a t Var :: t -> Expr a t Sum :: Expr a t -> Expr a t -> Expr a t 4 / 22
  7. Calculator Revisited data Expr a t where Literal :: a

    -> Expr a t Var :: t -> Expr a t Sum :: Expr a t -> Expr a t -> Expr a t ▶ So far: Expr a t contains only a literals ▶ type a is constant in the whole expression ▶ What if we want heterogeneous operations? > :t even even :: Integral a => a -> Bool 4 / 22
  8. Calculator Revisited data Expr a where Literal :: a ->

    Expr a Sum :: Expr a -> Expr a -> Expr a 4 / 22
  9. Calculator Revisited data Expr a where Literal :: a ->

    Expr a Sum :: Num a => Expr a -> Expr a -> Expr a Even :: Integral a => Expr a -> Expr Bool 4 / 22
  10. Calculator Revisited data Expr a where Literal :: a ->

    Expr a Sum :: Num a => Expr a -> Expr a -> Expr a Even :: Integral a => Expr a -> Expr Bool Cast :: (a -> b) -> Expr a -> Expr b 4 / 22
  11. A Fancy Calculator ▶ we now have a datatype which

    represents (some) arithmetic operations ▶ Apart from evaluating, what can we do with it? 5 / 22
  12. A Fancy Calculator ▶ we now have a datatype which

    represents (some) arithmetic operations ▶ Apart from evaluating, what can we do with it? ▶ print ▶ count operations ▶ optimize 5 / 22
  13. A Fancy Calculator ▶ we now have a datatype which

    represents (some) arithmetic operations ▶ Apart from evaluating, what can we do with it? ▶ print ▶ count operations ▶ optimize 5 / 22
  14. None
  15. 7 / 22

  16. The Essence of IO ▶ a representation of a computation

    ▶ ... which interacts with the world 8 / 22
  17. The Essence of IO ▶ a representation of a computation

    ▶ ... which interacts with the world 8 / 22
  18. The Essence of IO ▶ a representation of a computation

    ▶ ... which interacts with the world ▶ in Haskell: may contain all sorts of effects ▶ in GHC: opaque, non-inspectable 8 / 22
  19. The Essence of IO ▶ a representation of a computation

    ▶ ... which interacts with the world ▶ in Haskell: may contain all sorts of effects ▶ in GHC: opaque, non-inspectable ▶ but: a better world is possible 8 / 22
  20. IO as a DSL ▶ calculator: datatype with one constructor

    per operation ▶ terminal application: datatype with one constructor per operation? ▶ read from standard input ▶ write to standard output 9 / 22
  21. IO as a DSL ▶ calculator: datatype with one constructor

    per operation ▶ terminal application: datatype with one constructor per operation? ▶ read from standard input ▶ write to standard output ▶ open file ▶ read from file ▶ ... 9 / 22
  22. IO as a DSL ▶ calculator: datatype with one constructor

    per operation ▶ terminal application: datatype with one constructor per operation? ▶ read from standard input ▶ write to standard output ▶ open file ▶ read from file ▶ ... 9 / 22
  23. A Datatype for Terminal IO data Terminal a where ReadLine

    :: Terminal String WriteLine :: String -> Terminal () 10 / 22
  24. A Datatype for Terminal IO data Terminal a where ReadLine

    :: Terminal String WriteLine :: String -> Terminal () ▶ Terminal is an ordinary GADT ▶ nicely represents what we want ▶ But what to do with it? 10 / 22
  25. Free Structures “ Informally, a free object over a set

    A can be thought as being a “generic” algebraic structure over A: the only equations that hold between elements of the free object are those that follow from the defining axioms of the algebraic structure. Wikipedia: Free object ” 11 / 22
  26. Warning 12 / 22

  27. Free Monoids Monoid (M, ⊕, e) ▶ a set M

    ▶ an operation ⊕ : M × M → M ▶ a neutral element e ∈ M ▶ associativity: m1 ⊕ (m2 ⊕ m3) = (m1 ⊕ m2) ⊕ m3 ▶ neutrality: m ⊕ e = e ⊕ m = m 13 / 22
  28. Free Monoids Monoid (M, ⊕, e) ▶ a set M

    ▶ an operation ⊕ : M × M → M ▶ a neutral element e ∈ M ▶ associativity: m1 ⊕ (m2 ⊕ m3) = (m1 ⊕ m2) ⊕ m3 ▶ neutrality: m ⊕ e = e ⊕ m = m Question What is the simplest monoid over a given type t? 13 / 22
  29. Free Monoids Monoid (M, ⊕, e) ▶ a set M

    ▶ an operation ⊕ : M × M → M ▶ a neutral element e ∈ M ▶ associativity: m1 ⊕ (m2 ⊕ m3) = (m1 ⊕ m2) ⊕ m3 ▶ neutrality: m ⊕ e = e ⊕ m = m Answer List t 13 / 22
  30. Free Monads Monad m class Monad m where -- return

    a >>= k == k a -- m >>= return == m -- m >>= (\x -> k x >>= h) == (m >>= k) >>= h (>>=) :: m a -> (a -> m b) -> m b return :: a -> m a 14 / 22
  31. Free Monads Monad m class Monad m where -- return

    a >>= k == k a -- m >>= return == m -- m >>= (\x -> k x >>= h) == (m >>= k) >>= h (>>=) :: m a -> (a -> m b) -> m b return :: a -> m a Question What is the simplest monad over a given type constructor f? 14 / 22
  32. Free Monads Monad m class Monad m where -- return

    a >>= k == k a -- m >>= return == m -- m >>= (\x -> k x >>= h) == (m >>= k) >>= h (>>=) :: m a -> (a -> m b) -> m b return :: a -> m a Answer Well ... 14 / 22
  33. None
  34. Putting It All Together ▶ Recall our Terminal data type

    ▶ Stick it into FreeM and call it a day! data Terminal a where ReadLine :: Terminal String WriteLine :: String -> Terminal () 16 / 22
  35. Putting It All Together ▶ Recall our Terminal data type

    ▶ Stick it into FreeM and call it a day! ▶ ... except, no. data Terminal a where ReadLine :: Terminal String WriteLine :: String -> Terminal () 16 / 22
  36. Putting It All Together ▶ Recall our Terminal data type

    ▶ Stick it into FreeM and call it a day! ▶ ... except, no. ▶ It’s not even a Functor data Terminal a where ReadLine :: Terminal String WriteLine :: String -> Terminal () 16 / 22
  37. Free Functors Functor f class Functor f where -- fmap

    id == id -- fmap (f . g) == fmap f . fmap g fmap :: (a -> b) -> f a -> f b 17 / 22
  38. Free Functors Functor f class Functor f where -- fmap

    id == id -- fmap (f . g) == fmap f . fmap g fmap :: (a -> b) -> f a -> f b 17 / 22
  39. Free Functors Functor f class Functor f where -- fmap

    id == id -- fmap (f . g) == fmap f . fmap g fmap :: (a -> b) -> f a -> f b Question What is the simplest functor over a given type constructor f? 17 / 22
  40. Free Functors Functor f class Functor f where -- fmap

    id == id -- fmap (f . g) == fmap f . fmap g fmap :: (a -> b) -> f a -> f b Answer Coyoneda f 17 / 22
  41. Coyoneda? “ What is sometimes called the co-Yoneda lemma is

    a basic fact about presheaves (a basic fact of topos theory): it says that every presheaf is a colimit of representables and more precisely that it is the “colimit over itself of all the representables contained in it”. nLab ” 18 / 22
  42. Coyoneda? “ What is sometimes called the co-Yoneda lemma is

    a basic fact about presheaves (a basic fact of topos theory): it says that every presheaf is a colimit of representables and more precisely that it is the “colimit over itself of all the representables contained in it”. nLab ” 18 / 22
  43. None
  44. None
  45. Q & A  larsr h  larsrh

  46. Image Credits ▶ Randall Munroe, https://xkcd.com/1312/ ▶ Thomas Kluyver, Kyle

    Kelley, Brian E. Granger, https://github.com/ipython/xkcd-font ▶ Gerd Laures, https://golem.ph.utexas.edu/category/ 2012/01/vorsicht_funktor.html 22 / 22