Our goal is to build a simple calculator. We will not worry about the parsing as that requires input output for which we are not ready yet. We will only build the expression evaluator. We start by defining a data type that captures the syntax of expressions. Our expressions are simple and do not have variables.
1 |
|
Now the evaluator is easy.
1 |
|
Either
data typeYou might have noticed that that we do not handle the division by zero errors So we want to capture functions that evaluates to a value or returns an error. The Haskell library exports a data type called Either
which is useful in such a situation. For completeness, we give the definition of Either
. You can use the standard type instead.
data Either a b = Left a
| Right b
The data type Either
is used in haskell often is situation where a computation can go wrong like for example expression evaluation. It has two constructors Left
and Right
. By convention Right
is used for the correct value and Left for the error message: A way to remeber this convention is to remember that "Right is always right".
We would want our evaluator to return either an error message or a double. For convenience, we capture this type as Result
.
1 |
|
The above expression is a type alias. This means that Result a
is the same type as Either String a
. As far as the compiler is concerned, they are both same. We have already seen a type aliasing in action namely String
and [Char]
.
We are now ready to define the new evaluator. We first give its type
1 |
|
The definition of eval'
is similar to eval for constructors Const
, Plus
, Minus
and Mul
except that it has to ensure.
Ensure each of the sub expressions have not resulted a division by zero error.
If the previous condition is met has to wrap the result into a Result
data type using the Right
constructor.
Instead of explicit pattern matching we define a helper function for this calle app
that simplify this.
1 |
|
The constructor Div
has to be handled seperately as it is the only operator that generates an error. Again we write a helper here.
1 |
|
Now we are ready to define eval'
.
1 |
|
Let us load the code in the interpreter
1 |
|