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?
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.
Related
How can I edit the following code so that I don't have so many evaluators (which right now reflect various result types)? I want a single evaluator so that I don't know in advance the type of the result. I want one evaluator for the whole language. Do I need to add a value type for Exp to do this? How would this look like? What kind of value type and how would I edit the current eval functions in order to reflect this new polymorphic type?
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
data Exp = V Var
| B Bool
| MyInt Int
| And Exp Exp
| Or Exp Exp
| Not Exp
| Mult Exp Exp
| UnaryNeg Exp
| LEQ Exp Exp
| LESST Exp Exp
| Add Exp Exp
| POLYEQ Exp Exp
data Var = VZ |VS Var
eval:: Exp -> Int
eval (MyInt e1) = e1
eval (UnaryNeg e1) = - (eval e1)
eval (Mult e1 e2) = eval e1 * eval e2
eval (Add e1 e2) = eval e1 + eval e2
eval0:: Exp -> Bool
eval0 (B e1) = e1
eval0 (Not e1) = not (eval0 e1)
eval0 (And e1 e2) = (eval0 e1) && (eval0 e2)
eval0 (Or e1 e2) = (eval0 e1) || (eval0 e2)
eval0 (LEQ e1 e2) = eval e1 <= eval e2
eval0 (LESST e1 e2) = eval e1 < eval e2
eval1:: Exp -> Bool
eval1 (POLYEQ e1 e2) = eval0 e1 == eval0 e2
The standard solution is to have the expression type annotated with what type of result it represents. This will then be a Generalised Algebraic Data Type:
{-# LANGUAGE GADTs #-}
data Exp a where
V :: Var -> Exp a
B :: Bool -> Exp Bool
MyInt :: Int -> Exp Int
And :: Exp Bool -> Exp Bool -> Exp Bool
POLYEQ :: Exp a -> Exp a -> Exp Bool
...
Then you need only one evaluation function, whose result will be whatever the type represented by the expression:
eval :: Exp a -> a
eval (MyInt e1) = e1
eval (B e1) = e1
...
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?
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.
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.
I'm wrote a unique data type to express basic math (addition, mult, etc.) and it works - however, when I try to turn it into a Maybe statement, none of the math works. I believe it's a syntax error but I've tried extra parenthesis and so on and I can't figure it out. Usually Maybe statements are easy but I don't understand why it keeps throwing an issue.
This is the data type I created (with examples):
data Math = Val Int
| Add Math Math
| Sub Math Math
| Mult Math Math
| Div Math Math
deriving Show
ex1 :: Math
ex1 = Add1 (Val1 2) (Val1 3)
ex2 :: Math
ex2 = Mult (Val 2) (Val 3)
ex3 :: Math
ex3 = Div (Val 3) (Val 0)
Here is the code. The only Nothing return should be a division by zero.
expression :: Math -> Maybe Int
expression (Val n) = Just n
expression (Add e1 e2) = Just (expression e1) + (expression e2)
expression (Sub e1 e2) = Just (expression e1) - (expression e2)
expression (Mult e1 e2) = Just (expression e1) * (expression e2)
expression (Div e1 e2)
| e2 /= 0 = Just (expression e1) `div` (expression e2)
| otherwise = Nothing
I get the same error for every individual mathematical equation, even if I delete the others, so I'm certain it's syntax. The error makes it seem like a Maybe within a Maybe but when I do that e1 /= 0 && e2 /= 0 = Just (Just (expression e1)div(expression e2)), I get the same error:
* Couldn't match type `Int' with `Maybe Int'
Expected type: Maybe (Maybe Int)
Actual type: Maybe Int
* In the second argument of `div', namely `(expression e2)'
In the expression: Just (expression e1) `div` (expression e2)
In an equation for `expression':
expression (Div e1 e2)
| e1 /= 0 && e2 /= 0 = Just (expression e1) `div` (expression e2)
| otherwise = Nothing
|
56 | | e1 /= 0 && e2 /= 0 = Just (expression e1) `div` (expression e2)
| ^^^^^^^^^
What am I missing? It's driving me crazy.
So the first issue is precedence. Instead of writing:
Just (expression e1) * (expression e2)
You probably want:
Just (expression e1 * expression e2)
The second issue is the types. Take a look at the type of (*), for instance:
>>> :t (*)
(*) :: Num a => a -> a -> a
It says, for some type a that is a Num, it takes two as and returns one a. Specialised to Int, that would be:
(*) :: Int -> Int -> Int
But expression returns a Maybe Int! So we need some way to multiply with Maybes. Let's write the function ourselves:
multMaybes :: Maybe Int -> Maybe Int -> Maybe Int
multMaybes Nothing _ = Nothing
multMaybes _ Nothing = Nothing
multMaybes (Just x) (Just y) = Just (x * y)
So if either side of the multiplication has failed (i.e. you found a divide-by-zero), the whole thing will fail. Now, we need to do this once for every operator:
addMaybes Nothing _ = Nothing
addMaybes _ Nothing = Nothing
addMaybes (Just x) (Just y) = Just (x + y)
subMaybes Nothing _ = Nothing
subMaybes _ Nothing = Nothing
subMaybes (Just x) (Just y) = Just (x - y)
And so on. But we can see there's a lot of repetition here. Luckily, there's a function that does this pattern already: liftA2.
multMaybes = liftA2 (*)
addMaybes = liftA2 (+)
subMaybes = liftA2 (-)
Finally, there are two more small problems. First, you say:
expression (Div e1 e2)
| e2 /= 0 = Just (expression e1) `div` (expression e2)
But e2 isn't an Int! It's the expression type. You probably want to check if the result of the recursive call is 0.
The second problem is that you're unnecessarily wrapping things in Just: we can remove one layer.
After all of that, we can write your function like this:
expression :: Math -> Maybe Int
expression (Val n) = Just n
expression (Add e1 e2) = liftA2 (+) (expression e1) (expression e2)
expression (Sub e1 e2) = liftA2 (-) (expression e1) (expression e2)
expression (Mult e1 e2) = liftA2 (*) (expression e1) (expression e2)
expression (Div e1 e2)
| r2 /= Just 0 = liftA2 div (expression e1) r2
| otherwise = Nothing
where r2 = expression e2
There are two problems here:
Just (expression e1) + (expression e2)
is interpreted as:
(Just (expression e1)) + (expression e2)
So that means that you have wrapped the left value in a Just, whereas the other one is not, and this will not make much sense.
Secondly, both expression e1 and expression e2 have type Maybe Int, hence that means that you can not add these two together. We can perform pattern matching.
Fortunately there is a more elegant solution: we can make use of liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c for most of the patterns. For Maybe the liftM2 will take a function f :: a -> b -> c and two Maybes, and if both are Justs it will call the function on the values that are wrapped in the Justs and then wrap the result in a Just as well.
As for the division case, we will first have to obtain the result of the denominator with the expression function, and if that is a Just that is not equal to zero, then we can fmap :: Functor f => (a -> b) -> f a -> f b function to map a value in a Just (that of the numerator) given of course the numerator is a Just:
import Control.Monad(liftM2)
expression :: Math -> Maybe Int
expression (Val n) = Just n
expression (Add e1 e2) = liftM2 (+) (expression e1) (expression e2)
expression (Sub e1 e2) = liftM2 (-) (expression e1) (expression e2)
expression (Mult e1 e2) = liftM2 (*) (expression e1) (expression e2)
expression (Div e1 e2) | Just v2 <- expression e2, v2 /= 0 = fmap (`div` v2) (expression e1)
| otherwise = Nothing
or we can, like #RobinZigmond says, use (<$>) :: Functor f => (a -> b) -> f a -> f b and (<*>) :: Applicative f => f (a -> b) -> f a -> f b:
expression :: Math -> Maybe Int
expression (Val n) = Just n
expression (Add e1 e2) = (+) <$> expression e1 <*> expression e2
expression (Sub e1 e2) = (-) <$> expression e1 <*> expression e2
expression (Mult e1 e2) = (*) <$> expression e1 <*> expression e2
expression (Div e1 e2) | Just v2 <- expression e2, v2 /= 0 = (`div` v2) <$> expression e1
| otherwise = Nothing
I am having trouble with the Mod operator in Haskell Its inferring the wrong type based on what I have. Mod is at the bottom of eval. I am new to Haskell and am making an AST with expr for class. Here is the code I have so far. I am sure its a simple fix but cant seem to get it.
data Expr = Add Expr Expr
| Sub Expr Expr
| Mult Expr Expr
| EqualTo Expr Expr
| GreaterThan Expr Expr
| LessThan Expr Expr
| Mod Expr
| NotEqual Expr Expr
| Const Integer
| VarName String
| TrueE
| FalseE
deriving (Show,Eq)
eval :: Expr -> [(String, Integer)] -> Integer
eval (Add e1 e2) env = eval e1 env + eval e2 env
eval (Sub e1 e2) env = eval e1 env - eval e2 env
eval (Mult e1 e2) env = eval e1 env * eval e2 env
eval (EqualTo e1 e2) env | eval e1 env == eval e2 env = 1
| otherwise = 0
eval (GreaterThan e1 e2) env | eval e1 env > eval e2 env = 1
| otherwise = 0
eval (LessThan e1 e2) env | eval e1 env < eval e2 env = 1
| otherwise = 0
eval (NotEqual e1 e2) env | eval e1 env /= eval e2 env = 1
| otherwise = 0
eval (Mod e1) env = mod eval e1 env
I assume that you are building an evaluator for AST, which represents a mathematical expression.
Haskell function mod receives two arguments, but your AST receives only one argument, and function mod in your evaluator receives three arguments. Try to change the function eval and data Expr like this
data Expr =
| Mod Expr Expr
eval :: Expr -> [(String, Integer)] -> Integer
eval (Mod e1 e2) env = mod (eval e1 env) (eval e2 env)
In the above code, function mod receives two arguments, eval e1 env and eval e2 env respectively.
I was using the wrong notation for mod it should be
eval e1 env `mod` eval e2 env
Stupid mistake.. mod should be surrounded by back ticks.
For example I want to add two expressions e1 and e2
toString (Plus e1 e)= ??
I am guessing it would be something like
toString (Plus e1 e)= ((toString e1) ++ "+" ++ (toString e2))
I've made a few assumptions about how Plus is defined. With this code you can just type expr at the ghci prompt and ghci will print out the expression 100-30+100+30.
module Main where
data Expr =
Plus Expr Expr
| Minus Expr Expr
| Value Int
-- This works but is not as Haskell-y as using Show
toString (Plus e1 e2) = toString e1 ++ "+" ++ toString e2
toString (Minus e1 e2) = toString e1 ++ "-" ++ toString e2
toString (Value n) = show n
instance Show Expr where
show (Plus e1 e2) = show e1 ++ "+" ++ show e2
show (Minus e1 e2) = show e1 ++ "-" ++ show e2
show (Value n) = show n
expr = (Plus
(Minus (Value 100) (Value 30))
(Plus (Value 100) (Value 30)))