Monad



data W a = W a deriving Show



Show



return :: a -> W a

return x = W x



W

return

W

a -> b

W a -> W b



fmap :: (a -> b) -> (W a -> W b)

fmap f (W x) = W (f x)





a = W 1

b = fmap (+1) a



f



f :: Int -> W Int

f x = W (x+1)



f

fmap

f

f



bind :: (a -> W b) -> (W a -> W b)

bind f (W x) = f x



fmap



c = bind f (f 1)

d = bind f (bind f (f 1))



bind

fmap

fmap f = bind (return . f)

return

bind

g :: Int -> W Int -> W Int

g x (W y) = W (x+y)

W y

bind

h :: W Int -> W Int -> W Int

h (W x) (W y) = W (x+y)

>>=

bind

bind f x = x >>= f

W

fmap

W

Functor



> data W x = W x deriving Show



> instance Functor W where

> fmap f (W x) = W (f x)



> instance Monad W where

> return x = W x

> W x >>= f = f x



W

join :: W (W a) -> W a

Monad

Monad

Solutions to Exercises

g :: Int -> W Int -> W Int

g x (W y) = W (x+y)



g x y = ...



>>=

(+1)

>>=

Int -> Int

Int -> W Int

return



g x y = y >>= (return . (+x))



h :: W Int -> W Int -> W Int

h (W x) (W y) = W (x+y)

g



h x y = ...



g

x

\x -> g x y

Int -> W Int



h x y = x >>= (\x -> g x y)



h x y = x >>= flip g y

(m >>= f) >>= g = m >>= (\x -> f x >>= g)

m

W x

x



(W x >>= f) >>= g

= (f x) >>= g



W x >>= (\x -> f x >>= g)

= (\x -> f x >>= g) x

= f x >>= g



Update: I've added some solutions to exercises below.Haskell monads form a type class. And Haskell type classes are essentially interfaces shared by some types. So thetype class is a common API for talking to a bunch of different types. So the question is this: what's so special about this API?One way to grasp an API is to see concrete examples. Usually the monad API is introduced through containers or IO. But I think that the prototypical monad through which all others can be understood is much simpler - it's the trivial monad.APIs often capture design patterns, and the design pattern here is a one-way wrapper. We can wrap things but we can't unwrap them. We still want to be able to whatever we like to the wrapped data, but anything that depends on anything wrapped should itself be wrapped.Without further ado, here's a wrapper type:(Thebit is just so we can play with these things interactively.)Note how it doesn't add anything except some wrapping. And the first thing we need is to be able to wrap anything we like. We can do that easily with this function:(We could have just usedinstead of. But I'm heading towards a common API that will work with other types too, so it obviously can't be called.)And now we need one more thing - a way to manipulate wrapped data leaving it wrapped. There's an obvious idea. Given any functionwe write a function that converts it to a function. This is guaranteed to keep things under wraps. So here goesIt seems that we've finished. For example we can wrap a number and then increment it:But here's something we can't do. Define a functionlike this:It increments and returns a wrapped result. Now suppose we want to apply the underlying operation here twice, ie. we'd like to increment a number twice and return a wrapped result. We can't simply applytwice because (1) it'll doubly wrap our result and (2) it'll attempt to add 1 to a wrapped result, something that doesn't make sense.doesn't do what we want either. Try it in an interactive Haskell session. It seems we need a way to apply, unwrap the result and applyagain. But we've already said that we don't want to allow people to unwrap these things. We we need to provide a higher order function that does the unwrapping and application for us. As long as this function always gives us back something that is wrapped, our end users will never be able to unwrap anything. Here's an idea for such a function:Notice how it's very similar tobut is even simpler. So now we can try doubly, or triply, incrementingNotice howis more general than. In fact,And that's it. Usingandwe have achieved our goal of wrapping objects and freely manipulating wrapped objects while keeping them wrapped. What's more, we can chain functions that wrap without getting bogged down in multiple layers of wrapping. And that, really, sums up what a Haskell monad is all about.So here are a couple of exercises:(1) define a functionso that. Obviously that definition won't do - the left hand side has apattern so it's actually unwrapping. Rewrite this function so that the only unwrapping that happens is carried out by(2) define a functionso that. Again, no unwrapping.I'm hoping that after you've done these exercises you'll see how you can still work freely with data even though it's wrapped.In Haskell, it is more usual to use the operatorinstead ofwhereSo the last question is this: why would you ever wrap data like this? In practice people tend not to use the trivial monad very much. Nonetheless, you can see how it might be used to represent tainted data. Wrapped data is considered tainted. Our API never lets us forget when data is tainted and yet it still allows us to do what we like with it. Any time we try to do anything with tainted data the result is also tainted, exactly as we might expect. What I find interesting is that almost every monad, including IO, lists and even probability , can be thought of quite naturally as variations on taint. I hope to say more about this in the near future.Anyway, code above fails to compile because of some namespace clashes. Here's a complete definition ofthat really works. Note also that, which we showed we don't really need, allows us to makean instance oftoo:Exercise 3: Prove the three monad laws for. This should be almost trivial.Exercise 4: We can't completely unwrap things using the monad API. But we can unwrap one layer from things that are wrapped twice. So here's a nice puzzle: define a functionusing theAPI and no explicit unwrapping.In conclusion, most monad tutorials show what monads are, and how to use them. I hope I've given some additional insight into why theinterface consists precisely of the two functions it does. That insight should become clearer when I say more about taint.PS I've been a bit busy lately with planning for kitchen remodelling, lots of work and a new cat(!). I probably won't be posting very frequently for a few months.Some people have found the exercises tricky so I'm posting some solutions. I think it's a good sign that they're tricky, it means that there is some non-trivial stuff to be learnt from playing with this monad. It ought to figure more strongly in tutorials. In a sense it allows people to learn about monadicity in its purest form.Anyway, enough of that.Exercise 1: We wantso that. Start the definition like thisWe want to apply (+x) to y. But y is wrapped so we must useto apply it. Butdoesn't have the right type to be applied with, it's annot an. So we must compose withand we getExercise 2: We wantso that. Butis already fairly close. So again writeThe difference fromis thatis wrapped. So we want to applyto our wrapped value. This function is already of type. So we can just writeor justExercise 3: I'll just do the last one:is of the formfor someSo the LHS equals the RHS.Incidentally, you can get a long way with these problems by not thinking about what's going on! Instead, just write out the type signatures of all of the functions involved and try to stick them together like a jigsaw puzzle so that the final result has the right type. At each stage the arguments of each function must match the signature of the function so it really is like fitting the shapes of jigsaw pieces together. This isn't a foolproof strategy, but it often works.Anyway, feel free to ask questions if you're still stuck. Some of your questions may be answered here

Labels: haskell, monad