Online Book Reader

Home Category

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

By Root 575 0
<$> Just 2 <*> Just 8

Just 16

ghci> (++) <$> Just "klingon" <*> Nothing

Nothing

ghci> (-) <$> [3,4] <*> [1,2,3]

[2,1,0,3,2,1]

So now that we treat them as applicative values, Maybe a values represent computations that might have failed, [a] values represent computations that have several results (nondeterministic computations), IO a values represent values that have side effects, and so on.

Monads are a natural extension of applicative functors, and they provide a solution to the following problem: If we have a value with a context, m a, how do we apply to it a function that takes a normal a and returns a value with a context? In other words, how do we apply a function of type a -> m b to a value of type m a? Essentially, we want this function:

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

If we have a fancy value and a function that takes a normal value but returns a fancy value, how do we feed that fancy value into the function? This is the main concern when dealing with monads. We write m a instead of f a, because the m stands for Monad, but monads are just applicative functors that support >>=. The >>= function is called bind.

When we have a normal value a and a normal function a -> b, it’s really easy to feed the value to the function—we just apply the function to the value normally, and that’s it. But when we’re dealing with values that come with certain contexts, it takes a bit of thinking to see how these fancy values are fed to functions and how to take into account their behavior. But you’ll see that it’s as easy as one, two, three.

Getting Your Feet Wet with Maybe

Now that you have a vague idea of what monads are about, let’s make that idea a little more concrete. Much to no one’s surprise, Maybe is a monad. Here, we’ll explore it a bit more to see how it works in this role.

Note

Make sure you understand applicative functors at this point. (We discussed them in Chapter 11.) You should have a feel for how the various Applicative instances work and what kinds of computations they represent. To understand monads, you’ll be taking your existing applicative functor knowledge and upgrading it.

A value of type Maybe a represents a value of type a, but with the context of possible failure attached. A value of Just "dharma" means that the string "dharma" is there. A value of Nothing represents its absence, or if you look at the string as the result of a computation, it means that the computation has failed.

When we looked at Maybe as a functor, we saw that if we want to fmap a function over it, the function is mapped over what’s inside if that’s a Just value. Otherwise, the Nothing is kept, because there’s nothing to map it over!

ghci> fmap (++"!") (Just "wisdom")

Just "wisdom!"

ghci> fmap (++"!") Nothing

Nothing

As an applicative functor, Maybe functions similarly. However, with applicative functors, the function itself is in a context, along with the value to which it’s being applied. Maybe is an applicative functor in such a way that when we use <*> to apply a function inside a Maybe to a value that’s inside a Maybe, they both must be Just values for the result to be a Just value; otherwise, the result is Nothing. This makes sense. If you’re missing either the function or the thing you’re applying it to, you can’t make something up out of thin air, so you need to propagate the failure.

ghci> Just (+3) <*> Just 3

Just 6

ghci> Nothing <*> Just "greed"

Nothing

ghci> Just ord <*> Nothing

Nothing

Using the applicative style to have normal functions act on Maybe values works in a similar way. All the values must be Just values; otherwise, it’s all for Nothing!

ghci> max <$> Just 3 <*> Just 6

Just 6

ghci> max <$> Just 3 <*> Nothing

Nothing

And now, let’s think about how we would use >>= with Maybe. >>= takes a monadic value and a function that takes a normal value. It returns a monadic value and manages to apply that function to the monadic value. How does it do that if the function takes a normal value? Well, it must take into account the context of that monadic value.

In this case,

Return Main Page Previous Page Next Page

®Online Book Reader