user11340751
user11340751

Reputation:

Evaluating a nested data type

I'm trying to write a function that evaluates a nested boolean data type. My issue comes from comparing a data type within a data type. The first two (Lit and Or) compile fine but I don't understand how to incorporate the first type into the function of the SecondExpr. As I type it out, I feel like I'm taking the longest way possible when something shorter works.

Here are the two data types.

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

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

(Another issue I'm having is creating examples of SecondExpr to test because, conceptually, I see every Expr as the 6 different types of Expr. That means, for every Expr Expr there would be hundreds of guards.)

Below is the code so far:

eval :: SecondExpr -> Bool
eval (Lit n)                   = n
eval (Or e1 e2)
  | True && True               = True
  | True && False              = True
  | False && True              = True
  | otherwise                  = False
eval (EqualTo e1 e2)
  | (Add e1 e2) == (Add e1 e2) = True
  | (Sub e1 e2) == (Sub e1 e2) = True
  | (Mul e1 e2) == (Mul e1 e2) = True
  | (Div e1 e2) == (Div e1 e2) = True
  | otherwise                  = False
eval (LessThan e1 e2)
  | (Add e1 e2) == (Add e1 e2) = True
  | (Sub e1 e2) == (Sub e1 e2) = True
  | (Mul e1 e2) == (Mul e1 e2) = True
  | (Div e1 e2) == (Div e1 e2) = True
  | otherwise                  = False

This is the error I get:

    * No instance for (Eq Expr) arising from a use of `=='
    * In the expression: (Add e1 e2) == (Add e1 e2)
      In a stmt of a pattern guard for
                     an equation for `eval':
        (Add e1 e2) == (Add e1 e2)
      In an equation for `eval':
          eval (EqualTo e1 e2)
            | (Add e1 e2) == (Add e1 e2) = True
            | (Sub e1 e2) == (Sub e1 e2) = True
            | (Mul e1 e2) == (Mul e1 e2) = True
            | (Div e1 e2) == (Div e1 e2) = True
            | otherwise = False
   |
24 |   | (Add e1 e2)       == (Add e1 e2) = True
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

So I know my syntax is wrong but how do you substitute an Expression within the function of an Expression?

Upvotes: 0

Views: 120

Answers (1)

melpomene
melpomene

Reputation: 85767

You're going to need two evaluation functions:

evalNum :: Expr -> Int

and

evalBool :: SecondExpr -> Bool

Neither of them should use any guards (| ...).

For example, evalBool would look like this:

evalBool (Lit n) = n
evalBool (Or e1 e2) = evalBool e1 || evalBool e2
evalBool (EqualTo e1 e2) = evalNum e1 == evalNum e2
evalBool (LessThan e1 e2) = evalNum e1 < evalNum e2

Subexpressions are evaluated recursively with their corresponding eval functions, and the results are combined using appropriate Haskell operators (such as ||, ==, <).

Implementing evalNum is left as an exercise for the reader.

Upvotes: 4

Related Questions