Reputation: 418
Here i am trying to evaluate the expression in Haskell using defined values of Exp
data type. The function type would be eval :: Exp -> Int
and data type is this:
data Exp = Num Int
| Exp :+: Exp
| Exp :-: Exp
| Exp :*: Exp
| Exp :/: Exp
deriving (Show)
and values which i am trying to evaluate are these:
4 + 5 * 6 , respecting correct precedences of the operators
4 + 5 + 6 , respecting, that + binds left-associative
(4 + 3) * (5 - 2)
4 + (4 / (2 - 2))
So far this logic is working fine which is:
eval :: Exp -> Int
eval (Num a) = a
eval (a :+: b) = (eval a) + (eval b)
eval (a :-: b) = (eval a) - (eval b)
eval (a :*: b) = (eval a) * (eval b)
eval (a :/: b) = (eval a) `div` (eval b)
When i pass this i get 3
as output which is correct:
eval (Num 2 :+: Num 2 :-: Num 1)
output = 3
but i am confused how it evaluated the second part of the expression which :-:
what i understood the only pattern matched in first iteration was eval (a :+: b) = (eval a) + (eval b)
which returned 4
as output how it carries 4
to next iteration to perform the :-:
operation?
before that i was trying something like this:
eval :: Exp -> Int
eval (Num a) = a
eval (Num a :+: Num b) = eval (Num a) + eval (Num b)
eval (Num a :-: Num b) = eval (Num a) - eval (Num b)
eval (Num a :*: Num b) = eval (Num a) * eval (Num b)
eval (Num a :/: Num b) = eval (Num a) `div` eval (Num b)
it didn't give the desired results and then i just changed it to the first version. it worked fine but didn't get the proper semantics of it. Any help? Please don't hesitate to go into details. Thanks in advance.
Upvotes: 2
Views: 2007
Reputation: 532093
As pointed out in other answers, the problem is that all your constructors have the same default precedence: they are left-associative with high (9) precedence. You can change that using the infixl
directive.
data Exp = Num Int
| Exp :+: Exp
| Exp :-: Exp
| Exp :*: Exp
| Exp :/: Exp
deriving (Show)
-- Using the same precedences as (+), (-), (*), and (/)
infixl 6 :+:, :-:
infixl 7 :*:, :/:
Now eval $ Num 4 :+: Num 2 :*: Num 3
will correctly return 10 instead of 18.
Upvotes: 5
Reputation: 18249
I think the easiest way to follow what's going on here is just to follow the evaluation through one step at a time. Since as @WillNess has explained the default order of operation is from left to right, your code is evaluated as follows (each individual step comes directly from one of the lines of your definitioni of eval
):
eval ((Num 2 :+: Num 2) :-: Num 1)
eval (Num 2 :+: Num 2) - eval(Num 1)
(eval (Num 2 :+: Num 2)) - 1
(eval (Num 2) + eval (Num 2)) - 1
(2 + 2) - 1
4 - 1
3
I hope this makes it clear.
Upvotes: 1
Reputation: 71119
The default fixity for operators is infixl 9
(see 4.4.2 Fixity Declarations
).
You have not declared the fixity for your :+:
etc. operators.
This means that your expression gets parsed as
eval ((Num 2 :+: Num 2) :-: Num 1) :: Exp
-- Num 2 :: Exp
-- Num 2 :: Exp
-- Num 2 :+: Num 2 :: Exp
-- Num 1 :: Exp
-- (Num 2 :+: Num 2) :-: Num 1 :: Exp
So the evaluation proceeded as
eval ((Num 2 :+: Num 2) :-: Num 1) -- match with:
eval (a :-: b ) = (eval a) - (eval b)
= ....
Upvotes: 6