i am making tiny language. Let E be a tiny programming language that supports the declaration of arithmetic expressions and equality comparison on integers.
given the following data type E:
data E = IntLit Int
| BoolLit Bool
| Plus E E
| Minus E E
| Multiplies E E
| Exponentiate E E
| Equals E E
deriving (Eq, Show)
here is my code with above data it is working all of these.
data E = IntLit Int
| BoolLit Bool
| Plus E E
| Minus E E
| Multiplies E E
| Divides E E
| Equals E E
| log2Sim E E
deriving (Eq, Show)
eval :: E -> E
eval c#(IntLit i) = c
eval c#(BoolLit b) = c
eval (Plus a b) = plus (eval a) (eval b)
eval (Minus a b) = minus (eval a) (eval b)
eval (Multiplies a b) = multiplies (eval a) (eval b)
eval (Divides a b) = divides (eval a) (eval b)
eval (Equals a b) = equals (eval a) (eval b)
log2Sim :: E -> E
log2sim = case (eval x) of
IntLit i -> IntLit (logBase 2 i)
x1 -> "type error: can't take the log of a non-IntLit-valued expresstio" ++ show x1
plus (IntLit i) (IntLit j) = IntLit $ i + j
plus _ _ = error "Type error in addition"
minus (IntLit i) (IntLit j) = IntLit $ i - j
minus _ _ = error "Type error in subtraction"
multiplies (IntLit i) (IntLit j) = IntLit $ i * j
multiplies _ _ = error "Type error in multiplication"
divides (IntLit i) (IntLit j) = IntLit $ i `div` j
divides _ _ = error "Type error in division"
equals (IntLit i) (IntLit j) = BoolLit $ i == j
equals (BoolLit a) (BoolLit b) = BoolLit $ a == b
equals _ _ = error "Type error in equals"
when i compiled it, there are some errors.
what error is this?
A3.hs:56:7:
Couldn't match expected type `E' against inferred type `[Char]'
In the expression:
"type error: can't take the lof of a non-IntLit-valued expression: "
++
show x1
In a case alternative:
x1
-> "type error: can't take the lof of a non-IntLit-valued expression: "
++
show x1
In the expression:
case (eval x) of
IntLit i -> IntLit (logBase 2 i)
x1
-> "type error: can't take the lof of a non-IntLit-valued expression: "
++
show x1
There are many problems in your code:
All constructors must start with an upper-case letter. So data E = ... | log2Sim E E is incorrect. You also probably just want one E, hence for example data E = ... | Log E would fix both these problems.
You declared log2Sim but defined log2sim (notice the difference in capitalization). You also forgot to write the argument x to the left of the = in the definition. Fix both problems by writing
log2Sim x = ...
Strings are not valid expressions of type E. You probably wanted to follow the pattern in the rest of your code by calling error to turn your error string into an E. Thus:
x1 -> error $ "type error: can't take the log of a non-IntLit-valued expresstio" ++ show x1
logBase operates on Floating-point numbers, and Int is not one. There's a few ways to fix this, but the shortest distance between here and there is to convert to a Double and back. For example:
IntLit i -> IntLit . floor . logBase 2 . fromIntegral $ i
This is enough to make your code compile, though there may be other problems.
Related
Hi I need help with calculating a type. The whole program is suppose to take a string, parse it, and at the end, calculate a value. The string I start with can be like this: "let X = + 1 2 in * X 2 - X". When I parse it, I will get this: "Let (Vari X) (Sum (Lit 1) (Lit 2)) (Mul (Vari X) (Lit 2)))". At this moment, I can parse expressions like this "* + 2 3 * 2 + 6 - 2" and the previous. But I can not calculate the previous expression, "let X = + 1 2 in * X 2 - X". If someone could point me in the the right direction I would be happy, cause right now, I really don't know how I would make this work. Thanks
Code:
data Chara = A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z deriving (Eq, Show)
data Number = Single Int | Many Int Number deriving (Eq, Show)
data Expr = Lit Int | Sub Expr | Sum Expr Expr | Mul Expr Expr | Vari Chara | Let Expr Expr Expr
deriving Show
--Want to calculate this
--Let (Vari X) (Sum (Lit 1) (Lit 2)) (Mul (Vari X) (Lit 2)))
calculate :: Expr -> Int
calculate (Sub a) = let e = calculate a in (-e)
calculate (Sum a b) = let e = calculate a
r = calculate b
in (e+r)
calculate (Mul a b) = let e = calculate a
r = calculate b
in (e*r)
calculate (Lit a) = a
You'll need to perform variable substitution in your AST. I.e. you need a function
substitute :: (Chara, Expr) -> Expr -> Expr
which, given a pair of variable to substitute and expression to substitute it with will traverse the tree and perform that substitution. That basically means: if you find a Vari, just replace it with the substitution. If you find anything with subexpressions like Sum a b, recurse down into those subexpressions and then rebuild the operator with the results, i.e.
Sum (substitute s a) (substitute s b)
Then the calculate (Let var subst expr) = ... is a pretty straightforward invocation of the substitute function.
Works like a charm
calculate :: Expr -> Int
calculate (Sub a) = let e = calculate a in (-e)
calculate (Sum a b) = let e = calculate a
r = calculate b
in (e+r)
calculate (Mul a b) = let e = calculate a
r = calculate b
in (e*r)
calculate (Let a b c) = calculate (substitute (getCharaFromExpr a) b c)
calculate (Lit a) = a
substitute :: Chara -> Expr -> Expr -> Expr
substitute x y (Lit a) = Lit a
substitute x y (Vari a) | x == a = y
| otherwise = Vari a
substitute x y (Sum a b) = Sum (substitute x y a) (substitute x y b)
substitute x y (Mul a b) = Mul (substitute x y a) (substitute x y b)
substitute x y (Sub a) = Sub (substitute x y a)
substitute x y (Let a b c) = Let (substitute x y a) (substitute x y b) (substitute x y c)
I have those info on my haskell code:
data Symtable a = General a | Stack a
class Evaluable e where
eval :: (Num a, Ord a) => (Ident -> Maybe a) -> (e a) -> (Either String a)
typeCheck :: (Ident -> String) -> (e a) -> Bool
instance (Num a, Ord a) => Evaluable (NExpr a) where
eval f f2 = Left ("Undefined variable: ") --to make the code compilable
typeCheck f f2 = True --to make the code compilable
The thing is, eval function returns the evaluation of a numeric expression (for example 3 + 5, or x + 3), therefore I have to check the value of X on the symtable data but I haven't got it referenced on this function (I cannot edit the function header). How can I do it?
ident = string and Nexpr:
data NExpr n = Const n |
Var Ident |
Plus (NExpr n) (NExpr n) |
Minus (NExpr n) (NExpr n) |
Times (NExpr n) (NExpr n)
The first arugment to eval is a function that will look up the value of a name found in an expression. You ignore it when evaluating a Const value, use it when evaluating a Var value, and just pass it along to the recursive calls for the other cases.
instance (Num a, Ord a) => Evaluable (NExpr a) where
eval _ (Const n) = Right n
eval lookup (Var x) = case lookup x of
Nothing -> Left ("Undefined variable: " ++ x)
Just y -> Right y
eval lookup (Plus left right) = (+) <$> eval lookup left <*> eval lookup right
-- etc
Data type for arithmetic expressions with let bindings in haskell
Here's a variant of the original Expr type that adds variables (V) and let bindings (Let).
data Expr = C Float | V String
| Let [(String, Expr)] Expr
| Expr :+ Expr | Expr :- Expr
| Expr :* Expr | Expr :/ Expr
To help write evaluate, you may want to start with a function that does variable substitution:
data Expr = C Float | V String
| Let [(String, Expr)] Expr
| Expr :+ Expr | Expr :- Expr
| Expr :* Expr | Expr :/ Expr
deriving Show
-- | #sub var value e# replaces variables named #var# with the value #value#
-- wherever anywhere that variable occurs in expression #e#.
sub :: String -> Expr -> Expr -> Expr
-- "let x = y in x" = y
sub v1 value (V v2) | v1 == v2 = value
-- "let x = y in z" = z
sub _ _ e#(V _) = e
-- Constants are unaffected
sub _ _ c#(C _) = c
-- For operators, apply #sub a b# recursively to the operands.
sub a b (e1 :+ e2) = (sub a b e1) :+ (sub a b e2)
sub a b (e1 :- e2) = (sub a b e1) :- (sub a b e2)
sub a b (e1 :* e2) = (sub a b e1) :* (sub a b e2)
sub a b (e1 :/ e2) = (sub a b e1) :/ (sub a b e2)
-- The variable is shadowed by a let binding, so only substitute
-- into the bindings, and leave the body expression unmodified.
sub a b (Let bindings e) | bindingsContains a bindings =
Let (subIntoBindings a b bindings) e
-- Apply #sub a b# recursively to the body of the let expression.
sub a b (Let bindings body) =
Let (subIntoBindings a b bindings) (sub a b body)
bindingsContains :: String -> [(String, Expr)] -> Bool
bindingsContains x bindings =
Data.Maybe.isJust $ Data.List.find ((== x) . fst) bindings
subIntoBindings :: String -> Expr -> [(a, Expr)] -> [(a, Expr)]
subIntoBindings a b bindings = (fmap . fmap) (sub a b) bindings
I am creating a tiny language in Haskell that can perform simple math equations. The set up looks like this:
data E = IntLit Int
| BoolLit Bool
| Plus E E
| Minus E E
| Multiplies E E
| Exponentiate E E
| Equals E E
deriving (Eq, Show)
I have all of these working, but now I need to define a function for E that preserves the truth value of the expression by taking logs to base 2 if it is possible. If it isn't possible, the program may abort (e.g., with a Non-exhaustive pattern exception).
log2Sim :: E -> E
An example of running this should look like
> log2Sim (IntLit 8)
IntLit 3
Do I need to add log2Sim E to the language defined or is there another way? I'm trying to define it like so:
log2Sim :: E -> E
log2Sim (Log a) = log2sim (eval a)
log2sim (IntLit x) = IntLit $ logBase 2 x
But this is definitely not correct.
Let's always eval to see if we get an IntLit
Something like (not typechecked...)
log2Sim :: E -> E
log2sim x = case (eval x) of
IntLit i -> IntLit (logBase 2 i)
x1 -> error $ "type error: can't take the log of a non-IntLit-valued expression: " ++ show x1
Exercise 14.16-17 in Thompson asks me to add the operations of multiplication and (integer) division to the type Expr, which represents a simple language for arithmetic, then define the functions show and eval (evaluates an expression of type Expr) for Expr.
My solution works for each arithmetic operation except division:
data Expr = L Int
| Expr :+ Expr
| Expr :- Expr
| Expr :* Expr
| Expr :/ Expr
instance Num Expr where
(L x) + (L y) = L (x + y)
(L x) - (L y) = L (x - y)
(L x) * (L y) = L (x * y)
instance Eq Expr where
(L x) == (L y) = x == y
instance Show Expr where
show (L n) = show n
show (e1 :+ e2) = "(" ++ show e1 ++ " + " ++ show e2 ++ ")"
show (e1 :- e2) = "(" ++ show e1 ++ " - " ++ show e2 ++ ")"
show (e1 :* e2) = "(" ++ show e1 ++ " * " ++ show e2 ++ ")"
show (e1 :/ e2) = "(" ++ show e1 ++ " / " ++ show e2 ++ ")"
eval :: Expr -> Expr
eval (L n) = L n
eval (e1 :+ e2) = eval e1 + eval e2
eval (e1 :- e2) = eval e1 - eval e2
eval (e1 :* e2) = eval e1 * eval e2
E.g.,
*Main> (L 6 :+ L 7) :- L 4
((6 + 7) - 4)
*Main> it :* L 9
(((6 + 7) - 4) * 9)
*Main> eval it
81
it :: Expr
However, I am running into problems when I try to implement division. I don't understand the error message I receive when I try to compile the following:
instance Integral Expr where
(L x) `div` (L y) = L (x `div` y)
eval (e1 :/ e2) = eval e1 `div` eval e2
This is the error:
Chapter 14.15-27.hs:19:9:
No instances for (Enum Expr, Real Expr)
arising from the superclasses of an instance declaration
at Chapter 14.15-27.hs:19:9-21
Possible fix:
add an instance declaration for (Enum Expr, Real Expr)
In the instance declaration for `Integral Expr'
In the first place, I have no idea why defining div for the data type Expr requires me to define an instance of Enum Expr or Real Expr.
Well, that's the way the Integral typeclass is defined. For information, you can e.g. just type :i Integral into GHCi.
You'll get
class (Real a, Enum a) => Integral a where ...
which means any type a that should be Integral has to be Real and Enum first. C'est la vie.
Note that maybe you've got your types messed up quite a bit. Take a look at
instance Num Expr where
(L x) + (L y) = L (x + y)
(L x) - (L y) = L (x - y)
(L x) * (L y) = L (x * y)
This just allows you to add Expressions if they wrap plain numbers. I'm pretty sure you don't want that.
You want to add arbitrary expressions and you already have a syntax for this. It's just
instance Num Expr where
(+) = (:+)
(-) = (:-)
-- ...
This allows you to write (L 1) + (L 2) with perfectly normal syntax. Likewise, eval should not just reduce expressions but yield a number, and therefore have the type eval :: Expr -> Integer. Division is simple for that matter
eval (a :/ b) = (eval a) `div` (eval b)
which is defined since you just divide numbers.