Learn You a Haskell for Great Good! - Miran Lipovaca [147]
The Monad instance for Either e has an additional requirement. The type of the value contained in a Left—the one that’s indexed by the e type parameter—must be an instance of the Error type class. The Error type class is for types whose values can act like error messages. It defines the strMsg function, which takes an error in the form of a string and returns such a value. A good example of an Error instance is the String type! In the case of String, the strMsg function just returns the string that it got:
ghci> :t strMsg
strMsg :: (Error a) => String -> a
ghci> strMsg "boom!" :: String
"boom!"
But since we usually use String to describe the error when using Either, we don’t need to worry about this too much. When a pattern match fails in do notation, a Left value is used to signify this failure.
Here are a few examples of usage:
ghci> Left "boom" >>= \x -> return (x+1)
Left "boom"
ghci> Left "boom " >>= \x -> Left "no way!"
Left "boom "
ghci> Right 100 >>= \x -> Left "no way!"
Left "no way!"
When we use >>= to feed a Left value to a function, the function is ignored and an identical Left value is returned. When we feed a Right value to a function, the function is applied to what’s on the inside, but in this case, that function produced a Left value anyway!
When we try to feed a Right value to a function that also succeeds, we’re tripped up by a peculiar type error. Hmmm.
ghci> Right 3 >>= \x -> return (x + 100)
Ambiguous type variable `a' in the constraints: `Error a' arising from a use of `it' at `Show a' arising from a use of `print' at Probable fix: add a type signature that fixes these type variable(s) Haskell says that it doesn’t know which type to choose for the e part of our Either e a-typed value, even though we’re just printing the Right part. This is due to the Error e constraint on the Monad instance. So, if you get type errors like this one when using Either as a monad, just add an explicit type signature: ghci> Right 3 >>= \x -> return (x + 100) :: Either String Int Right 103 And now it works! Other than this little hang-up, using the error monad is very similar to using Maybe as a monad. Note In the previous chapter, we used the monadic aspects of Maybe to simulate birds landing on the balancing pole of a tightrope walker. As an exercise, you can rewrite that with the error monad so that when the tightrope walker slips and falls, you remember how many birds were on each side of the pole when he fell. Some Useful Monadic Functions In this section, we’re going to explore a few functions that operate on monadic values or return monadic values as their results (or both!). Such functions are usually referred to as monadic functions. While some of them will be brand new, others will be monadic counterparts of functions that you already know, like filter and foldl. Here, we’ll look at liftM, join, filterM, and foldM. liftM and Friends So, every monad is an applicative functor, and every applicative functor is a functor. The Applicative type class has a class constraint such that our type must be an instance of Functor before we can make it an instance of Applicative. Monad should have the same constraint for Applicative, as every monad is an applicative functor, but it doesn’t, because the Monad type class was introduced to Haskell long before Applicative. But even though every monad is a functor, we don’t need to rely on it having a Functor instance because of the liftM function.
When we started our journey to the top of Monad Mountain, we first looked at functors, which are for things that can be mapped over. Then we covered improved functors called applicative functors, which allow us to apply normal functions between several applicative values as well as to take a normal value and put it in some default context. Finally, we introduced monads as improved applicative functors, which add the ability for these values with context to somehow be fed into normal functions.