# Eval Division by Zero

## Eval: Division by Zero

Write a new version of your `eval`

function named `safeEval`

that will return an
error if the user tries to divide by zero. It should have the type:

`safeEval :: Expr -> Either String Int`

Here’s an example of the output you should expect when using `safeEval`

:

```
λ> eval $ Lit 10 `Div` Lit 0
*** Exception: divide by zero
λ> safeEval $ Lit 10 `Div` Lit 0
Left "Error: division by zero"
λ> safeEval $ Lit 10 `Div` Lit 10
Right 1
```

Hint: You may need to make quite a few changes to your `eval`

function to
complete this exercise, but no changes to your `Expr`

type should be necessary,
and you should not need to write any additional functions.

### Hints

## Click to reveal

Even though `Div`

is the only operation that might fail, you’ll need to return
an `Either`

value for any operation.

## Click to reveal

Remember that if you make a recursive call to `safeEval`

you’ll need to deal
with the fact that it will return an `Either`

instead of an evaluated `Int`

.

### Solution

## Click to reveal

Supporting safe division can be done with a relatively minor refactor of our
existing `eval`

code. Let’s start by copying our `eval`

function and renaming
it, then we can incrementally refactor it to support the behavior we want.

```
safeEval :: Expr -> Int
=
safeEval expr case expr of
Lit num -> num
Add arg1 arg2 -> eval' (+) arg1 arg2
Sub arg1 arg2 -> eval' (-) arg1 arg2
Mul arg1 arg2 -> eval' (*) arg1 arg2
Div arg1 arg2 -> eval' div arg1 arg2
where
eval' :: (Int -> Int -> Int) -> Expr -> Expr -> Int
=
eval' operator arg1 arg2 operator (safeEval arg1) (safeEval arg2)
```

We now have a `safeEval`

function, but it’s not all that safe. Let’s let the
types help us refactor this code into something that works the way we’d
like. We’ll start by changing the type of `safeEval`

to return `Either String Int`

:

`safeEval :: Expr -> Either String Int`

If we compile the program with just this change you’ll see that we’re getting
errors now. That makes sense, we’ve changed the stated type of the function, but
we haven’t actually changed any of the values that we’re turning. Let’s see what
happens if sprinkle a little optimism on our solution and update each of our
case branches to return a `Right`

value:

```
safeEval :: Expr -> Either String Int
=
safeEval expr case expr of
Lit num -> Right num
Add arg1 arg2 -> Right $ eval' (+) arg1 arg2
Sub arg1 arg2 -> Right $ eval' (-) arg1 arg2
Mul arg1 arg2 -> Right $ eval' (*) arg1 arg2
Div arg1 arg2 -> Right $ eval' div arg1 arg2
where
eval' :: (Int -> Int -> Int) -> Expr -> Expr -> Int
=
eval' operator arg1 arg2 operator (safeEval arg1) (safeEval arg2)
```

We’re getting closer, but we’ve still got a compile error. `eval'`

is making a
recursive call to `safeEval`

for each of our two arguments, but it’s still
expecting to get back `Int`

instead of the `Either String Int`

that we’re
returning now. Let’s update this function so that we properly handle errors in
the sub-expressions:

```
safeEval :: Expr -> Either String Int
=
safeEval expr case expr of
Lit num -> Right num
Add arg1 arg2 -> Right $ eval' (+) arg1 arg2
Sub arg1 arg2 -> Right $ eval' (-) arg1 arg2
Mul arg1 arg2 -> Right $ eval' (*) arg1 arg2
Div arg1 arg2 -> Right $ eval' div arg1 arg2
where
eval' :: (Int -> Int -> Int) -> Expr -> Expr -> Either String Int
=
eval' operator arg1 arg2 case safeEval arg1 of
Left err -> Left err
Right a ->
case safeEval arg2 of
Left err -> Left err
Right b -> Right $ operator a b
```

As you can see in ths example, we’ve had to updated `eval'`

to return an `Either String Int`

just like `safeEval`

. Since we don’t have a sensible default value
to use when we one of the expressions fails, the only option is to return the
error. Unfortunately, now we’ve got a problem with our original set of
changes. Let’s make another refactor to remove the `Right`

constructor wrapping
our calls to `safeEval`

since we’re going to be returning an `Either`

value
directly now:

```
safeEval :: Expr -> Either String Int
=
safeEval expr case expr of
Lit num -> Right num
Add arg1 arg2 -> eval' (+) arg1 arg2
Sub arg1 arg2 -> eval' (-) arg1 arg2
Mul arg1 arg2 -> eval' (*) arg1 arg2
Div arg1 arg2 -> eval' div arg1 arg2
where
eval' :: (Int -> Int -> Int) -> Expr -> Expr -> Either String Int
=
eval' operator arg1 arg2 case safeEval arg1 of
Left err -> Left err
Right a ->
case safeEval arg2 of
Left err -> Left err
Right b -> Right $ operator a b
```

With this set of changes, we finally have a compiling version of our function. Unfortunately, it’s still not actually doing any error handling:

```
$ Lit 10 `Div` Lit 0
λ safeEval Right *** Exception: divide by zero
```

It looks like we’re not quite done refactoring afterall. In this version of our
code, we’re passing an operator to `eval'`

, but the actual operator still can’t
deal with failure. If we want to safely handle division by zero, we’ll need to
update `eval'`

so that the operator it accepts returns an `Either String Int`

. We’ll also need to update *all* of the operators we pass in. In most
cases, we’ll be able to always return a `Right`

value, but for division we’ll
need to check the denominator. Let’s take a look at the final version:

```
safeEval :: Expr -> Either String Int
=
safeEval expr case expr of
Lit num -> Right num
Add arg1 arg2 -> eval' (opHelper (+)) arg1 arg2
Sub arg1 arg2 -> eval' (opHelper (-)) arg1 arg2
Mul arg1 arg2 -> eval' (opHelper (*)) arg1 arg2
Div arg1 arg2 -> eval' safeDiv arg1 arg2
where
safeDiv :: Int -> Int -> Either String Int
safeDiv a b| b == 0 = Left "Error: division by zero"
| otherwise = Right $ a `div` b
opHelper ::
Int -> Int -> Int) ->
(Int ->
Int ->
Either String Int
= Right $ a `op` b
opHelper op a b
eval' ::
Int -> Int -> Either String Int) ->
(Expr ->
Expr ->
Either String Int
=
eval' operator arg1 arg2 case safeEval arg1 of
Left err -> Left err
Right a ->
case safeEval arg2 of
Left err -> Left err
Right b -> operator a b
```

In this final version, we’ve added two new functions. `opHelper`

let’s us wrap
the operations like multiplication and addition that won’t fail, and `safeDiv`

which safely returns a `Left`

value when the denominator is zero. Finally, we’re
dropped the explicit `Right`

constructor in `eval'`

since `operator`

will now
return an `Either`

value. Let’s take a look to see this in action:

```
$ (Lit 1 `Div` Lit 0) `Add` (Lit 1 `Mul` Lit 2)
λ safeEval Left "Error: division by zero"
$ (Lit 1 `Div` Lit 1) `Add` (Lit 1 `Mul` Lit 2)
λ safeEval Right 3
```