# Haskell/Understanding monads/Maybe

We introduced monads using `Maybe`

as an example. The `Maybe`

monad represents computations which might "go wrong", in the sense of not returning a value; the definitions of `return`

and `(>>=)`

for `Monad`

amounting to:^{[1]}

return :: a -> Maybe a return x = Just x (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b (>>=) m g = case m of Nothing -> Nothing Just x -> g x

Now, we will present two additional examples, similar in spirit to the grandparents one in the previous chapter, and then conclude with some general points.

## Safe functions[edit]

The `Maybe`

datatype provides a way to make a safety wrapper around functions which can fail to work for a range of arguments. `head`

and `tail`

, which only work with non-empty lists, would be a good example of that. Another typical case, which we will explore in this section, are mathematical functions like `sqrt`

and `log`

, which (as far as real numbers are concerned) are only defined for non-negative arguments. For instance, our implementation of a "safe" square root function could be:

safeSqrt :: (Floating a, Ord a) => a -> Maybe a safeSqrt x | x >= 0 = Just (sqrt x) | otherwise = Nothing

We could now decide to write similar "safe functions" for all functions with limited domains, such as division, logarithm and inverse trigonometric functions (`safeDiv`

, `safeLog`

, `safeArcSin`

, etc.). However, when we try to combine them we run into a problem: they output a `Maybe a`

, but take an `a`

as an input. As a result, before each application, we have to check whether the previous operation was successful:

safeLogSqrt :: (Floating a, Ord a) => a -> Maybe a safeLogSqrt x = case safeSqrt x of Just root -> safeLog root Nothing -> Nothing

You can see the problem: the code looks ugly already when using one concatenation. If you had multiple concatenations the code would get even worse. This is in stark contrast to the easy concatenation that we get with "unsafe" functions:

unsafeLogSqrt = log . sqrt

This, however, is precisely the sort of issue monads can tackle: through `(>>=)`

, they allow us to concatenate computations easily, so that the result of one is fed to the next. `Maybe`

being a monad, we can achieve the desired effect very simply:

> return 1000 >>= safeSqrt >>= safeLog Just 3.4538776394910684 > return (-1000) >>= safeSqrt >>= safeLog Nothing

safeLogSqrt :: (Floating a, Ord a) => a -> Maybe a safeLogSqrt x = return x >>= safeSqrt >>= safeLog

Every additional operation is just another `>>= safeOperation`

term—no checks required, since `(>>=)`

takes care of that. To make things even easier, we can write the combination in a style which mirrors composition of "unsafe" functions with `(.)`

by using the `(<=<)`

operator from the `Control.Monad`

module:

import Control.Monad((<=<)) safeLogSqrt' = safeLog <=< safeSqrt

## Lookup tables[edit]

A lookup table is a table which relates *keys* to *values*. You *look up* a value by knowing its key and using the lookup table. For example, you might have a lookup table of contact names as keys to their phone numbers as the values in a phone book application. An elementary way of implementing lookup tables in Haskell is to use a list of pairs: `[(a, b)]`

. Here `a`

is the type of the keys, and `b`

the type of the values^{[2]}. Here's how the phone book lookup table might look like:

phonebook :: [(String, String)] phonebook = [ ("Bob", "01788 665242"), ("Fred", "01624 556442"), ("Alice", "01889 985333"), ("Jane", "01732 187565") ]

The most common thing you might do with a lookup table is look up values! However, this computation might fail. Everything is fine if we try to look up one of "Bob", "Fred", "Alice" or "Jane" in our phone book, but what if we were to look up "Zoe"? Zoe isn't in our phone book, so the lookup would fail. Hence, the Haskell function to look up a value from the table is a `Maybe`

computation (it is available from Prelude):

lookup :: Eq a => a -- a key -> [(a, b)] -- the lookup table to use -> Maybe b -- the result of the lookup

Let us explore some of the results from lookup:

Prelude> lookup "Bob" phonebook Just "01788 665242" Prelude> lookup "Jane" phonebook Just "01732 187565" Prelude> lookup "Zoe" phonebook Nothing

Now let's expand this into using the full power of the monadic interface. Say, we're now working for the government, and once we have a phone number from our contact, we want to look up this phone number in a big, government-sized lookup table to find out the registration number of their car. This, of course, will be another `Maybe`

-computation. But if they're not in our phone book, we certainly won't be able to look up their registration number in the governmental database! So what we need is a function that will take the results from the first computation, and put it into the second lookup, but only if we didn't get `Nothing`

the first time around. If we *did* indeed get `Nothing`

from the first computation, or if we get `Nothing`

from the second computation, our final result should be `Nothing`

.

comb :: Maybe a -> (a -> Maybe b) -> Maybe b comb Nothing _ = Nothing comb (Just x) f = f x

As you might have guessed by now, `comb`

is just `(>>=)`

; and so we can chain our computations together:

getRegistrationNumber :: String -- their name -> Maybe String -- their registration number getRegistrationNumber name = lookup name phonebook >>= (\number -> lookup number governmentalDatabase)

If we then wanted to use the result from the governmental database lookup in a third lookup (say we want to look up their registration number to see if they owe any car tax), then we could extend our `getRegistrationNumber`

function:

getTaxOwed :: String -- their name -> Maybe Double -- the amount of tax they owe getTaxOwed name = lookup name phonebook >>= (\number -> lookup number governmentalDatabase) >>= (\registration -> lookup registration taxDatabase)

Or, using the `do`

-block style:

getTaxOwed name = do number <- lookup name phonebook registration <- lookup number governmentalDatabase lookup registration taxDatabase

Let's just pause here and think about what would happen if we got a `Nothing`

anywhere. Trying to use `>>=`

to combine a `Nothing`

from one computation with another function will result in the `Nothing`

being carried on and the second function ignored (refer to our definition of comb above if you're not sure). That is, a `Nothing`

at *any stage* in the large computation will result in a `Nothing`

overall, regardless of the other functions! Thus we say that the structure of the `Maybe`

monad *propagates failures*.

## Summary[edit]

The key features of the `Maybe`

monad are that:

- It represents computations that could fail.
- It propagates failure.

Another trait of the `Maybe`

monad is that it is "open": if we have a `Just`

value, we can extract its associated value by pattern matching (which is what we did in the first implementation of `safeLogSqrt`

). That is is not true for all monads; often, they will be designed so as to help you by hiding unnecessary details. It is perfectly possible to make a "no-exit" monad, from which it is never possible to extract "pure" values, the obvious example being the `IO`

monad: in this way it is impossible not to notice that an operation involves input/output (and thereby side effects), because any I/O operation will carry around the `IO`

monad, which functions as a warning sign.

## Notes[edit]

- ↑ The definitions in the actual instance in
`Data.Maybe`

are written a little differently, but are fully equivalent to these. - ↑ Check the chapter about maps in Haskell in Practice for a different, and potentially more useful, implementation.