Online Book Reader

Home Category

Learn You a Haskell for Great Good! - Miran Lipovaca [127]

By Root 572 0
number of birds on the balancing pole and just makes Pierre slip and fall. We’ll call it banana:

banana :: Pole -> Maybe Pole

banana _ = Nothing

We can chain this function together with our bird landings. It will always cause our walker to fall, because it ignores whatever is passed to it and always returns a failure.

ghci> return (0, 0) >>= landLeft 1 >>= banana >>= landRight 1

Nothing

The value Just (1, 0) gets fed to banana, but it produces a Nothing, which causes everything to result in a Nothing. How unfortunate!

Instead of making functions that ignore their input and just return a predetermined monadic value, we can use the >> function. Here’s its default implementation:

(>>) :: (Monad m) => m a -> m b -> m b

m >> n = m >>= \_ -> n

Normally, passing some value to a function that ignores its parameter and always returns some predetermined value always results in that predetermined value. With monads, however, their context and meaning must be considered as well. Here’s how >> acts with Maybe:

ghci> Nothing >> Just 3

Nothing

ghci> Just 3 >> Just 4

Just 4

ghci> Just 3 >> Nothing

Nothing

If we replace >> with >>= \_ ->, it’s easy to see what’s happening.

We can replace our banana function in the chain with a >> and then a Nothing for guaranteed and obvious failure:

ghci> return (0, 0) >>= landLeft 1 >> Nothing >>= landRight 1

Nothing

What would this look like if we hadn’t made the clever choice of treating Maybe values as values with a failure context and feeding them to functions? Here’s how a series of bird landings would look:

routine :: Maybe Pole

routine = case landLeft 1 (0, 0) of

Nothing -> Nothing

Just pole1 -> case landRight 4 pole1 of

Nothing -> Nothing

Just pole2 -> case landLeft 2 pole2 of

Nothing -> Nothing

Just pole3 -> landLeft 1 pole3

We land a bird on the left, and then we examine the possibility of failure and the possibility of success. In the case of failure, we return a Nothing. In the case of success, we land birds on the right and then do the same thing all over again. Converting this monstrosity into a neat chain of monadic applications with >>= is a classic example of how the Maybe monad saves a lot of time when you need to successively do computations that are based on computations that might have failed.

Notice how the Maybe implementation of >>= features exactly this logic of seeing if a value is Nothing and acting on that knowledge. If the value is Nothing, it returns a Nothing immediately. If the value is not Nothing, it goes forward with what’s inside the Just.

In this section, we looked at how some functions work better when the values that they return support failure. By turning those values into Maybe values and replacing normal function application with >>=, we got a mechanism for handling failure pretty much for free. This is because >>= is supposed to preserve the context of the value to which it applies functions. In this case, the context was that our values were values with failure. So, when we applied functions to such values, the possibility of failure was always taken into account.

do Notation

Monads in Haskell are so useful that they got their own special syntax, called do notation. You already encountered do notation in Chapter 8, when we used it for gluing together several I/O actions into one. Well, as it turns out, do notation isn’t just for IO but can be used for any monad. Its principle is still the same: gluing together monadic values in sequence.

Consider this familiar example of monadic application:

ghci> Just 3 >>= (\x -> Just (show x ++ "!"))

Just "3!"

Been there, done that. Feeding a monadic value to a function that returns one—no big deal. Notice how when we do this, x becomes 3 inside the lambda. Once we’re inside that lambda, it’s just a normal value rather than a monadic value. Now, what if we had another >>= inside that function? Check this out:

ghci> Just 3 >>= (\x -> Just "!" >>= (\y -> Just (show x ++ y)))

Just "3!"

Ah, a nested use of >>=! In the outermost lambda, we feed Just "!" to the lambda \y -> Just (show

Return Main Page Previous Page Next Page

®Online Book Reader