110

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.

March 16, 2015

## Transcript

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

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 ﬁle ▶ read from ﬁle ▶ ... 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 ﬁle ▶ read from ﬁle ▶ ... 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 deﬁning axioms of the algebraic structure. Wikipedia: Free object ” 11 / 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

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

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

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

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