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?
True && Trueis the same as justTrue. A guard expression of| Truealways succeeds; it's like having no guard at all:eval (Or e1 e2) = True.SecondExpris for. You probably want eg.eval (Or e1 e2) = eval e1 || eval e2rather than what you've written, which is constantTrue. ForEqualTo, you'll need aneval'onExprto some equatable type, then justeval (EqualTo e1 e2) = eval' e1 == eval' e2(and you can see how to easily adapt that forLessThan). This also solves the issue of combinatorial explosion you observed, though as I said the overall design seems questionable but hard to be more helpful without more context.