Learn You a Haskell for Great Good! - Miran Lipovaca [124]
Note
Just a reminder: return is nothing like the return that’s in most other languages. It doesn’t end function execution. It just takes a normal value and puts it in a context.
The next function is >>=, or bind. It’s like function application, but instead of taking a normal value and feeding it to a normal function, it takes a monadic value (that is, a value with a context) and feeds it to a function that takes a normal value but returns a monadic value.
Next up, we have >>=. We won’t pay too much attention to it for now because it comes with a default implementation, and it’s rarely implemented when making Monad instances. We’ll take a closer look at it in Banana on a Wire in Banana on a Wire.
The final function of the Monad type class is fail. We never use it explicitly in our code. Instead, it’s used by Haskell to enable failure in a special syntactic construct for monads that you’ll meet later. We don’t need to concern ourselves with fail too much for now.
Now that you know what the Monad type class looks like, let’s take a look at how Maybe is an instance of Monad!
instance Monad Maybe where
return x = Just x
Nothing >>= f = Nothing
Just x >>= f = f x
fail _ = Nothing
return is the same as pure, so that one is a no-brainer. We do what we did in the Applicative type class and wrap it in a Just. The >>= function is the same as our applyMaybe. When feeding the Maybe a to our function, we keep in mind the context and return a Nothing if the value on the left is Nothing Again, if there’s no value, then there’s no way to apply our function to it. If it’s a Just, we take what’s inside and apply f to it.
We can play around with Maybe as a monad:
ghci> return "WHAT" :: Maybe String
Just "WHAT"
ghci> Just 9 >>= \x -> return (x*10)
Just 90
ghci> Nothing >>= \x -> return (x*10)
Nothing
There’s nothing new or exciting on the first line, since we already used pure with Maybe, and we know that return is just pure with a different name.
The next two lines showcase >>= a bit more. Notice how when we fed Just 9 to the function \x -> return (x*10), the x took on the value 9 inside the function. It seems as though we were able to extract the value from a Maybe without pattern matching. And we still didn’t lose the context of our Maybe value, because when it’s Nothing, the result of using >>= will be Nothing as well.
Walk the Line
Now that you know how to feed a Maybe a value to a function of type a -> Maybe b while taking into account the context of possible failure, let’s see how we can use >>= repeatedly to handle computations of several Maybe a values.
Pierre has decided to take a break from his job at the fish farm and try tightrope walking. He is not that bad at it, but he does have one problem: Birds keep landing on his balancing pole! They come and take a short rest, chat with their avian friends, and then take off in search of breadcrumbs. This wouldn’t bother him so much if the number of birds on the left side of the pole were always equal to the number of birds on the right side. But sometimes, all the birds decide that they like one side better. They throw him off balance, which results in an embarrassing tumble for Pierre (he is using a safety net).
Let’s say that Pierre keeps his balance if the number of birds on the left side of the pole and on the right side of the pole is within three. So if there’s one bird on the right side and four birds on the left side, he is okay. But if a fifth bird lands on the left side, he loses his balance and takes a dive.
We’re going to simulate