1
votes

The If data constructor (If BoolType Expr Expr) should evaluate the Boolean expression (first argument) and return the value of the second argument if it is true or return the third argument. I can construct an evaluation of the expression Expr but I don't understand how to incorporate the nested expression BoolType in order to evaluate an expression. A bit too twisty, I can't get my head around it.

Here's two data types:

data Expr = Val Int
          | Add Expr Expr
          | Sub Expr Expr
          | Mul Expr Expr
          | Div Expr Expr
          | If BoolType Expr Expr

data BoolType = Lit Bool
          | Or BoolType BoolType
          | EqualTo Expr Expr
          | LessThan Expr Expr

I wrote an expression that evaluates the type:

eval :: BoolType -> Bool
eval (Lit n)      = n
eval (Or e1 e2)       = eval e1 || eval e2
eval (EqualTo e1 e2)  = num e1 == num e2
eval (LessThan e1 e2) = num e1 < num e2

num :: Expr -> Int
num (Val n)          = n
num (Add e1 e2)      = num e1 + num e2
num (Sub e1 e2)      = num e1 - num e2
num (Mul e1 e2)      = num e1 * num e2
num (Div e1 e2)      = num e1 `div` num e2

It should evaluate out to any normal equation but how do I even incorporate an If boolean data type into the total equation?

2
Just add another branch to value that handles the If case. Did you encounter any specific problems with that? Also, why did you duplicate the code between num and value?Fyodor Soikin
It's technically two sections of code. What is the syntax for incorporating the If statement? My confusion is on the actual syntax. I'm unsure how to include an If.user11340751
Did you implement @melpomene's excellent answer to your similar question yesterday? If you've done that, handling the If case as well should be almost trivial.Robin Zigmond
They did an awesome job. My confusion was in how to treat cases of If which I thought had to be handled differently but I was way overthinking it.user11340751

2 Answers

2
votes

The evaluator functions currently have incomplete pattern matches:

*Q55835635> :l 55835635.hs
[1 of 1] Compiling Q55835635        ( 55835635.hs, interpreted )

55835635.hs:22:1: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for `num': Patterns not matched: (If _ _ _)
   |
22 | num (Val n)          = n
   | ^^^^^^^^^^^^^^^^^^^^^^^^^...
Ok, one module loaded.

Just add the missing pattern to num:

num :: Expr -> Int
num (Val n)          = n
num (Add e1 e2)      = num e1 + num e2
num (Sub e1 e2)      = num e1 - num e2
num (Mul e1 e2)      = num e1 * num e2
num (Div e1 e2)      = num e1 `div` num e2
num (If b e1 e2)     = if (eval b) then num e1 else num e2

You can now evaluate expressions, including those with If expressions:

*Q55835635> num $ Add (Val 40) (If (Lit True) (Val 2) (Val 0))
42

The rest of the functions aren't necessary.

0
votes

You can proceed with your approach, adding a suitable equation:

value (If cond e1 e2) = ifHelper (eval cond) (value e1) (value e2)

Then, you need to define your helper:

ifHelper :: Bool -> Maybe Int -> Maybe Int -> Maybe Int
ifHelper True  m1 m2 = ...
ifHelper False m1 m2 = ...

By the way, it is usually recommended to define the type of any function before starting to write the function itself. This helps both the programmer (who can reason about what type are the arguments) and the compiler (which can produce better error messages if something goes wrong).

Turning on warnings with the -Wall flag is also a good idea, since warnings can spot several potential errors.