### Yet Another Monad Tutorial (part 5: error-handling monads)

In the previous article we showed how to derive and use the `Maybe`

and list
monads. In this article and the next we're going to look at how to use monads
for error handling, also known as exception handling.

## Error-handling computations

The kind of computation that we want to model with our error-handling monads will have types that are schematically like this:

```
a --[possibly fail with a specified error condition]--> b
```

In words, this kind of computation maps an input value of type `a`

to an output
value of type `b`

, but instead of returning a value of type `b`

, it may fail
with a specified error condition. This is clearly very similar to the `Maybe`

monad. One difference is that all failures in the `Maybe`

monad are
indistinguishable (they return the `Nothing`

value). In contrast, in error
monads there are usually a variety of distinguishable error conditions that can
cause a computation to fail. Another difference is that when running error
handling computations it's desirable to have a mechanism for trapping errors and
recovering from error situations in a controlled way (this goes by the name
*exception handling* in most programming languages). As we'll see, using error
monads you can easily roll your own exception handling system.

## Error handling in Haskell

A programmer who wants to write code that may fail with specific error conditions has a large number of options in Haskell (maybe too large). Some of the more common ones include:

- The
`error`

function - Exceptions in the
`IO`

monad - Extensible exceptions
- Monadic exceptions

Let's look at these one at a time.

### The `error`

function

Most Haskell programmers are familiar with the `error`

function. It is
generally used just to abort a computation that cannot succeed. A good example
is calling a `factorial`

function with a negative integer:

```
factorial :: Integer -> Integer
factorial n | n < 0 = error "factorial: negative argument"
factorial 0 = 1
factorial n = n * factorial (n - 1)
```

The `error`

function has a very interesting type:

```
error :: String -> a
```

This means that the `error`

function takes a `String`

as argument and can
"return" a value of any type whatsoever. In fact, of course, the `error`

function *doesn't* return in the normal sense (that's the whole point: it's
called to abort a computation). Therefore, what `error`

's type really says is
that its return type is of no consequence and can be whatever makes the type
checker happy (in the `factorial`

example, `error`

's return type would thus be
`Integer`

).

Normally `error`

is not used as an exception-handling mechanism. In other
words, usually `error`

is not used in situations where errors need to be
recovered from. It's possible to catch errors thrown by `error`

, but the
recovery code has to be in the `IO`

monad. I don't want to go into this any
further (see the GHC documentation for more information), but I consider this to
be a hack. Functional code should be *functional*, and that means not having
weird behaviors that are not specified by the type signature. On the other
hand, I understand why this approach was taken. Consider this version of the
factorial function:

```
factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial (n - 1)
```

There's no ugly `error`

call here, but if `factorial`

is ever called with a
negative input, the function will go into an infinite loop. If you restricted
the second clause to just positive inputs:

```
factorial :: Integer -> Integer
factorial 0 = 1
factorial n | n > 0 = n * factorial (n - 1)
```

then if `factorial`

is called with a negative number, a pattern match error will occur
which will also abort the computation and not result in an `Integer`

being
returned. The `error`

function is a compromise to allow programmers to write
functions which are *total* (*i.e.* have defined and terminating behaviors for
all possible inputs) even when some of the inputs are invalid (*i.e.* the
function is conceptually a *partial* function, like `factorial`

).

We'll see a cleaner way to handle this below.

### Error handling in the `IO`

monad

The Haskell 98 standard specifies a way to deal with error conditions in the
`IO`

monad. There is a datatype called `IOException`

(aliased to `IOError`

),
which can contain various kinds of error-related information, as well as the
type of error condition. The number of error conditions is fixed (although
there is a catch-all `UserError`

category), so this isn't very sophisticated.
Errors are raised in the `IO`

monad using the `ioError`

function and can be
caught in the `IO`

monad with the `catch`

function. This approach is actually
quite similar to what we will derive below, except that it runs inside the `IO`

monad instead of inside a custom error-handling monad.

### Extensible exceptions

A more general version of the Haskell 98 error handling system is found in the
GHC module `Control.Exception`

, which implements *extensible exceptions* in the
`IO`

monad. I don't want to get into the details here, but the main idea is
that you can add your own exception types to the system as long as these types
are instances of the `Exception`

type class. This is an elegant system, except
for the fact that these exceptions can once again only be caught in the `IO`

monad.

Side note: There is a saying that the

`IO`

monad is the great "sin-bin" of the Haskell language, because so much functionality has been dumped into this monad which has nothing whatsoever to do with input or output. Using the`IO`

monad for error handling is a good example of this. Haskell programmers are increasingly moving away from over-using the`IO`

monad and towards a style where special-purpose monads are used to handle aspects of functionality that previously were dumped into the`IO`

monad.

### Monadic exceptions

The cleanest way to handle errors is to use a special-purpose error-handling monad, which is the topic of the rest of this article and the next.

## The `Either`

datatype

Recall the definition of the `Maybe`

datatype:

```
data Maybe a = Nothing | Just a
```

`Maybe`

is a type constructor which maps a type (like `Int`

) to a different type
(like `Maybe Int`

). Since `Maybe`

only takes a single type argument, it is a
*unary* type constructor. However, we don't want to use `Maybe`

for a
general-purpose error-handling system because we want to be able to represent
information about errors that occur (if all errors result in a `Nothing`

value,
there can be no error-specific information). It turns out that we can get this
with a slightly more complicated datatype called `Either`

. It looks like this:

```
data Either a b = Left a | Right b
```

`Either`

, like `Maybe`

, is a type constructor. However, unlike `Maybe`

, it
takes *two* type arguments, and is thus a *binary* type constructor. What
`Either`

allows you to do is to say of a data value "this data value can be one
of these two types, but nothing else", and it can do this for *any* two types.
For instance, let's consider the type `Either String Int`

. A value of this type
can be either `Left s`

where `s`

is a `String`

, or `Right i`

where `i`

is an
`Int`

. `Either`

has nothing fundamentally to do with error handling, but we
will be able to use it to create an error handling system. In this case, the
convention we will adopt is that the `Left`

constructor will represent error
values and the `Right`

constructor will represent successful results of
computations.

For instance, if we wanted a version of integer division that checks for divide-by-zero conditions, we might write something like this:

```
safe_divide :: Int -> Int -> Either String Int
safe_divide _ 0 = Left "divide by zero"
safe_divide i j = Right (i `div` j)
```

Let's test it in `ghci`

:

```
ghci> 36 `safe_divide` 6
Right 6
ghci> 1 `safe_divide` 0
Left "divide by zero"
```

The good news is that we have a clean way to say that a computation has failed, and we can give information about why it failed as well. The bad news is that this function is going to be tedious to use. For instance:

```
-- f i j k = i + j / k
f :: Int -> Int -> Int -> Either String Int
f i j k =
case j `safe_divide` k of
Left msg -> Left msg
Right r -> Right (i + r)
```

This is pretty complicated considering what we are trying to do. In addition,
the output type (`Either String Int`

) is different from the input types (which
are all `Int`

s), so it's going to be hard to compose functions which return
these `Either`

values with functions that don't. But let's press on for now and
deal with those problems later.

We can use the `Either`

datatype to represent multiple kinds of error
conditions. For instance, with integer division, we might want to fail if the
two numbers are not evenly divisible as well as checking for division by zero.
We can improve our `safe_divide`

function accordingly:

```
safe_divide :: Int -> Int -> Either String Int
safe_divide _ 0 = Left "divide by zero"
safe_divide i j | i `mod` j /= 0 = Left "not divisible"
safe_divide i j = Right (i `div` j)
```

Now we have a division function for integers that can handle two error
conditions. However, it's not easy to write code which detects which of the two
conditions occurred. For instance, we might have situations where dividing two
integers which are not evenly divisible is OK (we just throw away the remainder)
but division by zero is probably never going to be OK. Let's try to write this
using our `safe_divide`

function:

```
divide :: Int -> Int -> Either String Int
divide i j = case i `safe_divide` j of
Left "divide by zero" -> Left "divide by zero"
Left "not divisible" -> Right (i `div` j)
Right k -> Right k
```

Do you see what the problem is here? We are actually pattern-matching on an error message! That was not supposed to be the purpose of error messages. Furthermore, if the error message was long and complicated, not only would it be tedious to re-type, but there is a good chance that we would make a typo which would show up as a run-time error, because this pattern match is not exhaustive (even though we know that these are the only errors that can occur). There has to be a better way. And there is! Let's define an algebraic datatype for our errors:

```
data ArithmeticError =
DivideByZero
| NotDivisible
-- could add more cases here
deriving Show
```

The `deriving Show`

part is just so that `ArithmeticError`

values can be printed
when testing the code in `ghci`

. Now our definitions become:

```
safe_divide :: Int -> Int -> Either ArithmeticError Int
safe_divide _ 0 = Left DivideByZero
safe_divide i j | i `mod` j /= 0 = Left NotDivisible
safe_divide i j = Right (i `div` j)
divide :: Int -> Int -> Either ArithmeticError Int
divide i j = case i `safe_divide` j of
Left DivideByZero -> Left DivideByZero
Left NotDivisible -> Right (i `div` j)
Right k -> Right k
```

Notice that the types of our functions are no longer `Either String Int`

;
because the error representation has changed to use `ArithmeticError`

s, the
types are `Either ArithmeticError Int`

. What's nice about the definition of
`divide`

is that if we forget one of the `ArithmeticError`

cases, the compiler
will let us know (assuming we've enabled exhaustive pattern match checking,
which I always do).

One limitation is that if we decide later that we want to add another
constructor to the `ArithmeticError`

datatype, we will potentially need to
modify a lot of code to handle the extra case. A more extensible approach (and
the one used in GHC's `Control.Exception`

module) is to use an *existential
type* for error values. This is a fascinating topic, but it would lead us too
far afield, so I'm going to stick to the simple algebraic datatype in what
follows.

Let's recap. Our error-handling functions will return values which have the
type `Either e a`

, with a custom error type `e`

as the datatype used in the
`Left`

constructor. This custom error type will itself be an algebraic datatype
with one constructor for each class of errors. The arguments to the constructor
(if any) will provide whatever information we want to attach to that class of
errors. And with this, we can write clean functions that either succeed or
result in specific errors.

What we *haven't* done is shown how to use these error-handling functions in a
way which is not completely gross. Every time we call a function that may
result in an error condition, we have to use a `case`

statement to check for
those error conditions. This is very reminiscent of the case in the C
programming language where some functions return error codes which have to be
analyzed before continuing in case an error occurred. Doing this is tedious in
C, and it's just as tedious in Haskell. In other languages, this kind of
problem led to the development of exception-handling systems. What's Haskell
going to do about it? Hmmm, I wonder...

## Making an error-handling monad

When we work with monads, we are working with monadic functions which have the
general type `a -> m b`

for arbitrary types `a`

and `b`

, and for a type
constructor `m`

. This type constructor must be a *unary* type constructor
*i.e.* a "type function" which maps a type to a type. We saw this with the
`Maybe`

monad, where `Maybe`

is a unary type constructor which maps a type (say,
`Int`

) to another type (`Maybe Int`

). In this case, the type of the monadic
functions will thus be `a -> Maybe b`

.

All well and good, but how do we adapt this result to work with error-handling types? First of all, we have to figure out what the type of our monadic functions is going to be. It should come as no surprise that the basic error-handling function type is:

```
a -> Either e b
```

for arbitrary types `a`

and `b`

, and for some error type `e`

, which will
typically be an algebraic data type like the `ArithmeticError`

type shown
above. Note that this is the error-handling counterpart to a non-error-handling
function of type `a -> b`

. Note also that via currying we can have
error-handling functions with arbitrary numbers of arguments, for instance:

```
a -> b -> Either e c
```

The `safe_divide`

and `divide`

functions above happen to have two input
arguments (of type `Int`

) and one output argument (of type ```
Either
ArithmeticError Int
```

), so they are cases in point. Without loss of generality,
we will only deal with one-argument functions of the form

```
a -> Either e b
```

while realizing that through currying, our functions can actually have as many arguments as we want.

The problem now is that it might appear that the type

```
a -> Either e b
```

is not in the shape of the standard monadic function type

```
a -> m b
```

because this requires a unary type constructor `m`

and what we have is the
binary type constructor `Either`

. But Haskell allows us to curry type
constructor "applications" as well as function applications! In other words, we
can rewrite the `Either`

-containing type signature as:

```
a -> (Either e) b
```

and `Either e`

is a perfectly valid *unary* type constructor, since it is a
partially-applied *binary* type constructor (applied here to some error type
`e`

). In the case of our `ArithmeticError`

type, we can write

```
a -> (Either ArithmeticError) b
```

and `Either ArithmeticError`

is a unary type constructor: it takes as its
"input" a type (`b`

) and produces the type `Either ArithmeticError b`

.

The reason that this is important is that it allows us to treat `Either e`

(for
any error type `e`

) as a monad! Compare:

```
a -> m b -- general type of monadic functions
a -> (Either e) b -- type of monadic error-handling functions
```

So the monad `m`

in the first case is just `Either e`

for error-handling monads.
In fact, of course, the parentheses can be omitted, so we write these types as
just

```
a -> Either e b
```

as you'd expect. Given all this, it shouldn't come as a surprise that the definition of the relevant monad would look like this:

```
instance Monad (Either e) where
(>>=) = {- definition of >>= for error-handling monads -}
return = {- definition of return for error-handling monads -}
```

As before, we will first derive the `>>=`

operator based on what we want the
monad to do for us, and then we'll derive the `return`

function using the monad
laws.

### Deriving the `>>=`

operator

In the context of our error-handling monad, the `>>=`

operator will have the
type:

```
(Either e) a -> (a -> (Either e) b) -> (Either e) b
```

which we might as well write without superfluous parentheses as:

```
Either e a -> (a -> Either e b) -> Either e b
```

The interpretation of this is similar to that of the `Maybe`

monad. We are
taking the result of an error-handling computation as our input. That input has
the type `Either e a`

, which means that it is "either" an error of type `e`

or a
non-erroneous value of type `a`

. If it's an error, that error is just passed
through unchanged. If it's not an error, the value of type `a`

is extracted and
passed to the function of type `a -> Either e b`

, yielding the result of type
`Either e b`

. Writing the definition is very straightforward:

```
(>>=) :: Either e a -> (a -> Either e b) -> Either e b
Left err >>= f = Left err
Right val >>= f = f val
```

What this means in practice is that if you have a bunch of error-handling
computations being carried out one after another, and an error happens in one of
them, all the computations subsequent to that error (represented by the monadic
function `f`

, which may be made up of a bunch of other monadic functions
composed together) are not carried out; instead, the error value is the return
value of the entire computation.

Although this definition is plausible, we still have to verify that it doesn't
violate the monad laws. Before we do that, we have to define what `return`

means in this monad.

### Deriving the `return`

function

The type of the `return`

function in this monad is:

```
return :: a -> Either e a
```

Recall that the type `Either e a`

is:

```
data Either e a = Left e | Right a
```

It wouldn't make much sense to return a `Left`

value from `return`

; for one
thing, no error has occurred, and even if it had, which error would we use? So
it's plausible that `return`

will return a `Right ???`

value for some `???`

. We
need to fill in this definition:

```
return :: a -> Either e a
return x = Right ???
```

Since we know nothing whatsoever about the value `x`

other than that it has the
type `a`

, the simplest thing we can put on the right-hand side is just `x`

.
This also makes sense given that we know that `return`

is the monadic equivalent
of the identity function. So this definition is plausible:

```
return :: a -> Either e a
return x = Right x
```

Again, we need to check that this doesn't violate the monad laws.

### The monad laws

The first monad law, written in terms of `return`

and `>>=`

, is:

```
return x >>= f == f x
```

Using our definitions for the `Either e`

monad, we have:

```
return x >>= f
= Right x >>= f -- definition of return
= f x -- definition of >>=
-- Q.E.D.
```

Check. The second monad law is:

```
mv >>= return == mv
```

Let's see if this works:

```
-- Case 1: mv == Left err
mv >>= return
= Left err >>= return -- definition of mv
= Left err -- definition of >>=
= mv -- definition of mv
-- Case 2: mv == Right val
mv >>= return
= Right val >>= return -- definition of mv
= return val -- definition of >>=
= Right val -- definition of return
= mv -- definition of mv
-- Both cases correct, so Q.E.D.
```

Yup. That was pretty easy. Now let's attempt the somewhat harder task of proving monad law 3 correct. The third law is:

```
(mv >>= f) >>= g == mv >>= (\x -> (f x >>= g))
```

And so then:

```
-- Case 1: mv == Left err
-- Left-hand side:
(mv >>= f) >>= g
= (Left err >>= f) >>= g -- definition of mv
= Left err >>= g -- definition of >>=
= Left err -- definition of >>=
-- Right-hand side:
mv >>= (\x -> (f x >>= g))
= Left err >>= (\x -> (f x >>= g)) -- definition of mv
= Left err -- definition of >>=
-- Case 1 checks out.
-- Case 2: mv == Right val
-- Left-hand side:
(mv >>= f) >>= g
= (Right val >>= f) >>= g -- definition of mv
= (f val) >>= g -- definition of >>=
= f val >>= g -- remove unnecessary parentheses
-- Right-hand side:
mv >>= (\x -> (f x >>= g))
= Right val >>= (\x -> (f x >>= g)) -- definition of mv
= (\x -> (f x >>= g)) val -- definition of >>=
= (f val >>= g) -- function application (beta reduction)
= f val >>= g -- remove unnecessary parentheses
-- Case 2 checks out, so Q.E.D.
```

And we're done. `Either e`

is indeed a monad. The complete definition of the
monad is thus:

```
instance Monad (Either e) where
return x = Right x -- or just: return = Right
(Left x) >>= f = Left x
(Right x) >>= f = f x
```

Notice that the specific error type `e`

is irrelevant. This means that ```
Either
e
```

is a monad *regardless* of what error type `e`

is used. So ```
Either
ArithmeticError
```

is a monad, `Either String`

is a monad, and ```
Either [any other
type]
```

is a monad too. (Generic code like this gives Haskell programmers a warm
fuzzy feeling.) Of course, as we saw above, the error type *does* matter, but
not for the monad-ness (monadnicity?) of the computation.

Also notice that if we wanted to, we could write the definition of `>>=`

in a
slightly different (but equivalent) way:

```
xx >>= f =
case xx of
Left x -> Left x
Right x -> f x
```

All we've done here is replace two equations with an explicit `case`

statement,
which is something that Haskell compilers do for us when compiling code. This
way of writing the `>>=`

operator will help you solve an exercise I give below.

Now that we've established that, it's time to see it in action (pun intended!).

## Example: using the `Either e`

monad in a computation

Consider this very simple function on integers:

```
-- f i j k = i / k + j / k
f :: Int -> Int -> Int -> Int
f i j k = (i `div` k) + (j `div` k)
```

We use `div`

instead of the `/`

operator because `/`

is not defined for integers
in Haskell. This function will fail if `k`

is `0`

. In addition, if we want to
have it fail when either `i`

or `j`

are not evenly divisible by `k`

, we're out
of luck; because of the way `div`

works, it will just throw away the remainders.

Let's try it out:

```
ghci> f 6 4 2
5
ghci> f 6 4 0
*** Exception: divide by zero
ghci> f 6 3 2
4
```

`f 6 4 2`

is a nice case where both of the first two arguments are divisible by
the third, giving the expected result `5`

. When the third argument is `0`

we
get an exception, and when the second argument is not divisible by the third,
the remainder is thrown away.

Before I show you the monadic version of this, I want to rewrite the function
`f`

slightly:

```
-- f' i j k = i / k + j / k
f' :: Int -> Int -> Int -> Int
f' i j k =
let q1 = i `div` k
q2 = j `div` k
in q1 + q2
```

What we're doing here is giving names to all the subexpressions, so that only one arithmetic expression is computed on a line. This may look different from the previous example, but after it passes through GHC's optimization passes, both forms reduce to the exact same code. You'll see why I did this shortly.

Now let's write this code using an `Either ArithmeticError Int`

return type, but
without using the monadic machinery. We get this:

```
-- g i j k = i / k + j / k
g :: Int -> Int -> Int -> Either ArithmeticError Int
g i j k =
case i `safe_divide` k of
Left err1 -> Left err1
Right q1 ->
case j `safe_divide` k of
Left err2 -> Left err2
Right q2 -> Right (q1 + q2)
```

This is kind of gross, but we'll let that pass for now. Let's test it:

```
ghci> g 6 4 2
Right 5
ghci> g 6 4 0
Left DivideByZero
ghci> g 6 3 2
Left NotDivisible
```

This is nice in the sense that whenever there is an error (as we have defined
it) we get a specific error result. Now let's rewrite this using the ```
Either
e
```

monad:

```
-- g' i j k = i / k + j / k
g' :: Int -> Int -> Int -> Either ArithmeticError Int
g' i j k =
do q1 <- i `safe_divide` k
q2 <- j `safe_divide` k
return (q1 + q2)
```

This gives the exact same results as the previous version:

```
ghci> g' 6 4 2
Right 5
ghci> g' 6 4 0
Left DivideByZero
ghci> g' 6 3 2
Left NotDivisible
```

However, the function `g'`

is much simpler and clearer than `g`

because it
doesn't have to explicitly handle any of the error cases. When an error case
occurs, it is returned as the result of the function, but if not, the correct
result of a subexpression is bound to a name (`q1`

or `q2`

), and that result can
be used in later parts of the computation. So what monads buy us here is
exactly what they buy us for the `Maybe`

monad: the code is a lot simpler to
write. The more complicated the error-handling function, the more important
this will be.

Note that, as always, we can rewrite this without using the `do`

-notation as
follows:

```
-- g'' i j k = i / k + j / k
g'' :: Int -> Int -> Int -> Either ArithmeticError Int
g'' i j k =
i `safe_divide` k >>= \q1 ->
j `safe_divide` k >>= \q2 ->
return (q1 + q2)
```

This is identical to the function `g'`

. We rarely do this in practice (except
for very short functions) because the `do`

form is usually more readable, but it
would be a really good exercise at this point to make sure that you understand
the desugaring of the `do`

form into the form with explicit `>>=`

operators.

NOTE: There are situations in which the translation from the`do`

-notation into the version with explicit`>>=`

operators is a bit more complicated than what I've described. If the left-hand side of the`->`

is a single name, it's valid, but if it's something more complicated, a pattern-match failure can result, which will result in the`fail`

function of the monad being called. We will talk about this at length in the next article, because there will be a connection between this and certain error-handling type classes that we will be discussing.

Once you've done that, you should then take the definition of `g''`

and reduce
it to the function `g`

using the definitions of `>>=`

and `return`

for the
`Either e`

monad. (See the hint above.)

The last lines in `g'`

and `g''`

contain an explicit `return`

. However, you can
put `return`

s anywhere, since all they do is lift regular values into the
`Either e`

monad. For instance, we could define a function `gg`

as follows:

```
gg :: Int -> Int -> Int -> Either ArithmeticError Int
gg i j k =
do q1 <- i `safe_divide` k
x1 <- return (q1 * 2 - i)
q2 <- j `safe_divide` k
x2 <- return (q2 * 3 + j)
return (q1 * x1 + q2 * x2)
```

What this does isn't important, but it does show that you can put `return`

s in
the interior of a monadic function. Lines of the form:

```
x <- return y
```

are converting `y`

to a monadic value and then unpacking that value into `x`

.
Thus `x`

and `y`

must have the same type. I emphasize again that `return`

in
Haskell has *nothing whatsoever* to do with returning from a function! Make
sure you understand this before you continue.

The last thing I want to do in this section is to contrast three functions: `f`

,
`f'`

, and `g'`

:

```
f :: Int -> Int -> Int -> Int
f i j k = (i `div` k) + (j `div` k)
f' :: Int -> Int -> Int -> Int
f' i j k =
let q1 = i `div` k
q2 = j `div` k
in q1 + q2
g' :: Int -> Int -> Int -> Either ArithmeticError Int
g' i j k =
do q1 <- i `safe_divide` k
q2 <- j `safe_divide` k
return (q1 + q2)
```

As you can see, the monadic function `g'`

is structurally very similar to the
non-monadic function `f'`

. Unlike `f`

or `f'`

, though, `g'`

will catch
division-by-zero errors and not-divisible errors and report them in a usable
form. The monadic machinery has made it possible to turn grungy error-handling
functions like `g`

into error-handling functions no grungier than (non
error-handling) functions like `f'`

. You might wonder if you can go further
than this and write monadic functions like `g'`

in a form like the non-monadic
function `f`

, *i.e.* something like:

```
-- not valid Haskell!
g''' :: Int -> Int -> Int -> Either ArithmeticError Int
g''' i j k = (i `safe_divide` k) + (j `safe_divide` k)
```

The answer is: no, you can't. The reason is that, in a monad, you are enforcing
a certain order of operations: the expression `i `safe_divide` k`

will be
evaluated before the expression `j `safe_divide` k`

. This is necessary in
order to let us abort the computation early if the first expression results in
an error. On the other hand, for normal Haskell expressions like ```
(i `div` k)
+ (j `div` k)
```

the order of operations is not specified; Haskell is a lazy
language and can evaluate this expression in whatever order it wants. So,
unfortunately, we can't make our monadic computation look just as simple as the
corresponding non-monadic one, but we can come pretty close.

NOTE: Some monadic computations care more about sequencing than others. For any computation in the`IO`

monad and most computations in state monads (to be discussed later), sequencing is absolutely essential (for instance, if you print two strings one after the other, you want them to come out in the order you specified, not in some other order!). For some computations in other monads, sequencing is less important. In the present case, whether`i `safe_divide` k`

or`j `safe_divide` k`

is evaluated first is not that important; the error handling is the same for both functions and whether one expression or the other fails first is irrelevant. Nevertheless, whether we like it or not, monads impose the sequencing of operations on their computations and we have to be explicit about this when writing monadic code.

So far, we've used the `Either e`

monad and the `ArithmeticError`

datatype to
achieve two things:

writing an error-handling function which gives specific errors for all the error conditions we care about;

writing these functions in a clean way that doesn't involve lots of ugly nested

`case`

statements and redundant boilerplate code.

What we *haven't* done yet is to create a system in which errors can be
recovered from in a selective manner. This is what other languages offer in
their exception handling systems. As we will see next time, in Haskell it's
incredibly easy to define your own exception handling system in a way which
builds upon what we've just done.

## Next time

In the next installment we'll finish our discussion of error-handling monads by
talking about the `MonadError`

and `Error`

type classes, two type classes that
will enable us to use the monadic machinery we've already developed to do
exception handling (error recovery) in a reasonable way.

## Comments