I've started to work through http://www.cs.nott.ac.uk/~pszgmh/monads for a intro on functional programming course. What better way to try and understand stuff than to actually try and test the code.
Alas, on the second page I encounter the following:
data Expr = Val Int | Div Expr Expr
eval :: Expr -> Int
eval (Val n) = n
eval (Div x y) = eval x `div` eval y
Which produces an error when I try to run it. I'm not quite sure why this happens.
When I try
eval (Val 4) `div` eval (Val 2)
in the repl-loop, it works just fine, but
eval 4 `div` eval 2
Ends in a type inference error.
When I update my definition to the following:
data Expr = Val Int | Div Expr Expr
eval :: Expr -> Int
eval (Val n) = n
eval (Div x y) = eval (Val x) `div` eval (Val y)
I get a type error in definition. What is wrong with the first definition?
The course uses Hugs by the way.
What eval expects is an argument of a type that eval is defined for. Looking at the signature, it requires an argument of type Expr, either a Val or a Div. eval 4 means that you're passing an Int to the function. For that to work, eval would have to be defined as:
eval :: Int -> Int
By writing (Val 4), you are invoking one of the data constructors of Expr type, creating a new value of type Expr, which you can pass to eval and make the compiler happy.
Related
I need to write a code that evaluates a string of operations and outputs the resulting integer of that string. I wrote something but it's not working and would like some help. I need to use fold since it is easier but I'm sure what's wrong. This is on Haskell and using Emacs.
evalExpr :: String -> Int
evalExpr xs = foldl 0 xs where
f v x | x == "+" = (+) v
| x == "-" = (-) v
| x == " " = 0
| otherwise = read v :: Int
For example:
evalExpr "2+4+5-8"
the output should be: 3
evalExpr ""
the output should be: 0
This is because it should read the string left to right.
You can do as #5ndG suggested. However, to evaluate a string of operations, using parsec is a better way. Here is an example for your case:
module EvalExpr where
-- You need parsec to do parsing work, and the following are just example
-- modes for your simple case.
import Text.Parsec
import Text.Parsec.Char
import Text.Parsec.String
-- A data structure for your simple arithmetic expresssion
data Expr = Lit Int
| Plus Expr Expr
| Minus Expr Expr
deriving Show
-- Evaluate an Expr to an integer number
eval :: Expr -> Int
eval (Lit n) = n
eval (Plus e1 e2) = eval e1 + eval e2
eval (Minus e1 e2) = eval e1 - eval e2
-- The following do the parsing work
-- Parser for an integer number
int :: Parser Expr
int = Lit . read <$> (many1 digit <* spaces) -- A number may be followed by spaces
-- Parser for operators "Plus" and "Minus"
plus, minus :: Parser (Expr -> Expr -> Expr)
plus = Plus <$ char '+' <* spaces
minus = Minus <$ char '-' <* spaces
-- Parser for Expr
expr :: Parser Expr
expr = chainl int (plus <|> minus) (Lit 0)
-- Evalute string to an integer
evalExpr :: String -> Int
evalExpr s = case parse expr "" s of
Left err -> error $ show err
Right e -> eval e
The above is just an simple example of using parsec. If your actual case is more complex, you'll need more work to do. So learning to use parsec is necessary. The intro_to_parsing is a good start. Also in the package description are there some learning resources.
By the way, Text.Parsec.Expr in parsec can parse an expression more conveniently, but above all, you need to know the basic of parsec.
Happy learning!
You're not far off something that works on your examples. Try this:
evalExpr :: String -> Int
evalExpr xs = foldl f (0 +) xs 0
f :: (Int -> Int) -> Char -> (Int -> Int)
f v ch | ch == '+' = (v 0 +)
| ch == '-' = (v 0 -)
| ch == ' ' = v
| otherwise = (v (read [ch] :: Int) +)
So the main difference to yours is that the accumulator in the fold is a function that takes in one Int and produces one Int, instead of just being an Int.
A famous Haskell book has an exercise (spoiler alert) that asks to write functor, applicative and monad instances for a simplified data type of mathematical expressions. And no, this is not my homework for a course.
The following typechecks:
data Expr a = Var a | Val Int | Add (Expr a) (Expr a) deriving Show
instance Functor Expr where
fmap f (Var x) = Var $ f x
fmap f (Add e1 e2) = Add (fmap f e1) (fmap f e2)
fmap _ (Val x) = Val x
instance Applicative Expr where
pure x = Var x
(Val x) <*> _ = Val x
(Var f) <*> e = f <$> e
(Add f g) <*> e = Add (f <*> e) (g <*> e)
instance Monad Expr where
return = pure
(Val x) >>= _ = Val x
(Var x) >>= f = f x
(Add e1 e2) >>= f = Add (e1 >>= f) (e2 >>= f)
However, the last part of the question asks to explain what bind does in this case, with an example. I think an even better question would be: what kinds of useful operations can you do with these abstractions? So I started to consider this, with the following expression:
expr :: Expr Char
expr = Add (Add (Var 'x') (Var 'y')) (Add (Var 'x') (Val 1))
The functor instance allows me to substitute a different name for a variable:
λ> (\v -> if v == 'x' then 't' else v) <$> expr
Add (Add (Var 't') (Var 'y')) (Add (Var 't') (Val 1))
But using it to substitute values for variables doesn't really seem to work:
λ> (\v -> if v == 'x' then 2 else 3) <$> expr
Add (Add (Var 2) (Var 3)) (Add (Var 2) (Val 1))
Here, however, the monad comes to the rescue:
λ> expr >>= (\v -> Val (if v == 'x' then 2 else 3))
Add (Add (Val 2) (Val 3)) (Add (Val 2) (Val 1))
With the help of the monad, it seems even possible to substitute expressions for a variable, here t+2 is substituted for x:
λ> expr >>= (\v -> if v == 'x' then Add (Var 't') (Val 2) else pure v)
Add (Add (Add (Var 't') (Val 2)) (Var 'y')) (Add (Add (Var 't') (Val 2)) (Val 1))
But what else? What would be meaningful uses of the applicative? What other useful operations could we do with the monad?
The applicative instance corresponds to substituting for variables where the Expr-level structure of the substitution doesn't depend on the variable. For example, if you were processing this expression in the context of a linear programming problem and wanted to replace each variable Var 'x' with a sum of two variables, one which is always positive and one which is always negative, you could write:
> import Control.Applicative
> expr <**> Add (Var (:"pos")) (Var (:"neg"))
Add (Add (Add (Var "xpos") (Var "xneg"))
(Add (Var "ypos") (Var "yneg")))
(Add (Add (Var "xpos") (Var "xneg")) (Val 1))
>
The key here is that every variable is replaced with the same template Add (Var "_pos") (Var "_neg") where the new variables in the template have names that can depend on the original variable name. That's what makes this operation applicative.
As an aside, note that substituting a Val Int for each Var Char isn't an applicative operation unless the same value is substituted for each variable -- the value of the Int is part of the Expr-level structure and can't depend on the variable name.
Because the monad instance can replace variables with an Expr that depends on the variable name, it can perform more general substitutions.
Ultimately, the Functor instance allows you to change variable names, the Monad instance allows you to substitute variables with arbitrary expressions, and the Applicative instance provides a limited sort of template substitution that just isn't very interesting or useful for this particular data structure.
That's really all they can do, though there is one generalization that you touched on with your failed attempt to use the Functor instance to substitute values. These instances can change the type from Expr Char to some other Expr b. For example, if you were compiling an expression to a bytecode that referenced variables by memory pointers, then suddenly variable "renaming" via the Functor becomes a little more interesting:
type Location = Int
symtab :: [(Char, Int)]
symtab = [('x', 4096), ('y', 4100)] -- memory addresses
> fmap (fromJust . flip lookup symtab) expr
Add (Add (Var 4096) (Var 4100)) (Add (Var 4096) (Val 1))
>
Substitution is pretty much what bind does, but that's a pretty useful tool. For instance you can make a function that eliminates all variables by lookups in an [(a,Int)] (and an extra Int as default value if the variable is not in the list).
I suppose the Monad instance could be made to do other stuff, for instance if it simplifies the expression when it rebuilds Add's (so Add (Val x) (Val y) is reduced to Val (x+y)), the function I mentioned above would always reduce the result to (Val n). Not sure you want to do that though.
The Applicative instance does not let you do anything you can not already do with the Monad instance (prove this by implementing <*> using >>= and pure).
I understand how to create and evaluate a simple data-type Expr. For example like this:
data Expr = Lit Int | Add Expr Expr | Sub Expr Expr | [...]
eval :: Expr -> Int
eval (Lit x) = x
eval (Add x y) = eval x + eval y
eval (Sub x y) = eval x - eval y
So here is my question: How can I add Variables to this Expr type, which should be evaluated for its assigned value? It should look like this:
data Expr = Var Char | Lit Int | Add Expr Expr [...]
type Assignment = Char -> Int
eval :: Expr -> Assignment -> Int
How do I have to do my eval function now for (Var Char) and (Add Expr Expr)? I think I figured out the easiest, how to do it for Lit already.
eval (Lit x) _ = x
For (Var Char) I tried a lot, but I cant get an Int out of an Assignment.. Thought It would work like this:
eval (Var x) (varname number) = number
Well if you model your enviroment as
type Env = Char -> Int
Then all you have is
eval (Var c) env = env c
But this isn't really "correct". For one, what happens with unbound variables? So perhaps a more accurate type is
type Env = Char -> Maybe Int
emptyEnv = const Nothing
And now we can see whether a variable is unbound
eval (Var c) env = maybe handleUnboundCase id (env c)
And now we can use handleUnboundCase to do something like assign a default value, blow up the program, or make monkeys climb out of your ears.
The final question to ask is "how are variables bound?". If you where looking for a "let" statement like we have in Haskell, then we can use a trick known as HOAS (higher order abstract syntax).
data Exp = ... | Let Exp (Exp -> Exp)
The HOAS bit is that (Exp -> Exp). Essentially we use Haskell's name-binding to implement our languages. Now to evaluate a let expression we do
eval (Let val body) = body val
This let's us dodge Var and Assignment by relying on Haskell to resolve the variable name.
An example let statement in this style might be
Let 1 $ \x -> x + x
-- let x = 1 in x + x
The biggest downside here is that modelling mutability is a royal pain, but this was already the case when relying on the Assignment type vs a concrete map.
You need to apply your Assignment function to the variable name to get the Int:
eval (Var x) f = f x
This works because f :: Char -> Int and x:: Char, so you can just do f x to get an Int.
Pleasingly this will work across a collection of variable names.
Example
ass :: Assignment
ass 'a' = 1
ass 'b' = 2
meaning that
eval ((Add (Var 'a') (Var 'b')) ass
= eval (Var 'a') ass + eval (Var 'b') ass
= ass 'a' + ass 'b'
= 1 + 2
= 3
Pass the assignment functions through to other calls of eval
You need to keep passing the assignment function around until you get integers:
eval (Add x y) f = eval x f + eval y f
Different order?
If you're allowed to change the types, it seems more logical to me to put the assignment function first and the data second:
eval :: Assignment -> Expr -> Int
eval f (Var x) = f x
eval f (Add x y) = eval f x + eval f y
...but I guess you can think of it as a constant expression with varying variables (feels imperative)rather than a constant set of values across a range of expressions (feels like referential transparency).
I would recommend using Map from Data.Map instead. You could implement it something like
import Data.Map (Map)
import qualified Data.Map as M -- A lot of conflicts with Prelude
-- Used to map operations through Maybe
import Control.Monad (liftM2)
data Expr
= Var Char
| Lit Int
| Add Expr Expr
| Sub Expr Expr
| Mul Expr Expr
deriving (Eq, Show, Read)
type Assignment = Map Char Int
eval :: Expr -> Assignment -> Maybe Int
eval (Lit x) _ = Just x
eval (Add x y) vars = liftM2 (+) (eval x vars) (eval y vars)
eval (Sub x y) vars = liftM2 (-) (eval x vars) (eval y vars)
eval (Mul x y) vars = liftM2 (*) (eval x vars) (eval y vars)
eval (Var x) vars = M.lookup x vars
But this looks clunky, and we'd have to keep using liftM2 op every time we added an operation. Let's clean it up a bit with some helpers
(|+|), (|-|), (|*|) :: (Monad m, Num a) => m a -> m a -> m a
(|+|) = liftM2 (+)
(|-|) = liftM2 (-)
(|*|) = liftM2 (*)
infixl 6 |+|, |-|
infixl 7 |*|
eval :: Expr -> Assignment -> Maybe Int
eval (Lit x) _ = return x -- Use generic return instead of explicit Just
eval (Add x y) vars = eval x vars |+| eval y vars
eval (Sub x y) vars = eval x vars |-| eval y vars
eval (Mul x y) vars = eval x vars |*| eval y vars
eval (Var x) vars = M.lookup x vars
That's a better, but we still have to pass around the vars everywhere, this is ugly to me. Instead, we can use the ReaderT monad from the mtl package. The ReaderT monad (and the non-transformer Reader) is a very simple monad, it exposes a function ask that returns the value you pass in when it's run, where all you can do is "read" this value, and is usually used for running an application with static configuration. In this case, our "config" is an Assignment.
This is where the liftM2 operators really come in handy
-- This is a long type signature, let's make an alias
type ExprM a = ReaderT Assignment Maybe a
-- Eval still has the same signature
eval :: Expr -> Assignment -> Maybe Int
eval expr vars = runReaderT (evalM expr) vars
-- evalM is essentially our old eval function
evalM :: Expr -> ExprM Int
evalM (Lit x) = return x
evalM (Add x y) = evalM x |+| evalM y
evalM (Sub x y) = evalM x |-| evalM y
evalM (Mul x y) = evalM x |*| evalM y
evalM (Var x) = do
vars <- ask -- Get the static "configuration" that is our list of vars
lift $ M.lookup x vars
-- or just
-- evalM (Var x) = ask >>= lift . M.lookup x
The only thing that we really changed was that we have to do a bit extra whenever we encounter a Var x, and we removed the vars parameter. I think this makes evalM very elegant, since we only access the Assignment when we need it, and we don't even have to worry about failure, it's completely taken care of by the Monad instance for Maybe. There isn't a single line of error handling logic in this entire algorithm, yet it will gracefully return Nothing if a variable name is not present in the Assignment.
Also, consider if later you wanted to switch to Doubles and add division, but you also want to return an error code so you can determine if there was a divide by 0 error or a lookup error. Instead of Maybe Double, you could use Either ErrorCode Double where
data ErrorCode
= VarUndefinedError
| DivideByZeroError
deriving (Eq, Show, Read)
Then you could write this module as
data Expr
= Var Char
| Lit Double
| Add Expr Expr
| Sub Expr Expr
| Mul Expr Expr
| Div Expr Expr
deriving (Eq, Show, Read)
type Assignment = Map Char Double
data ErrorCode
= VarUndefinedError
| DivideByZeroError
deriving (Eq, Show, Read)
type ExprM a = ReaderT Assignment (Either ErrorCode) a
eval :: Expr -> Assignment -> Either ErrorCode Double
eval expr vars = runReaderT (evalM expr) vars
throw :: ErrorCode -> ExprM a
throw = lift . Left
evalM :: Expr -> ExprM Double
evalM (Lit x) = return x
evalM (Add x y) = evalM x |+| evalM y
evalM (Sub x y) = evalM x |-| evalM y
evalM (Mul x y) = evalM x |*| evalM y
evalM (Div x y) = do
x' <- evalM x
y' <- evalM y
if y' == 0
then throw DivideByZeroError
else return $ x' / y'
evalM (Var x) = do
vars <- ask
maybe (throw VarUndefinedError) return $ M.lookup x vars
Now we do have explicit error handling, but it isn't bad, and we've been able to use maybe to avoid explicitly matching on Just and Nothing.
This is a lot more information than you really need to solve this problem, I just wanted to present an alternative solution that uses the monadic properties of Maybe and Either to provide easy error handling and use ReaderT to clean up that noise of passing an Assignment argument around everywhere.
In an exam today I was asked to create an expression evaluation tree in Haskell.
Usually the answer is as simple as:
data Expr = Value Integer
| Add Expr Expr
| Sub Expr Expr
| Mul Expr Expr
And to evaluate it, you just use a function such as:
eval :: Expr -> Integer
eval (Value x) = x
eval (Add l r) = eval l + eval r
eval (Sub l r) = eval l - eval r
eval (Mul l r) = eval l * eval r
However today, we were given a data type:
data Op = Add
| Sub
| Mul
So I assumed to create the expression tree I could just do:
data Expr = Value Integer
| Op Expr Expr
And use the same eval function. However, I have since written that function and loaded it into GHCI, but it does not seem to work.
Could anyone explain why this doesn't work?
You must define a data constructor (providing a name)
data Expr = Value Integer | Compute Op Expr Expr
^^^^^^^
then
eval :: Expr -> Integer
eval (Value x) = x
eval (Compute Add l r) = eval l + eval r
and so on.
:)
When doing calculations modulo n with large numbers, you will encounter huge performency penalties when doing for example mod (123456789^987654321) n. Instead you have to use your own ^ that internally calculates mod n also for intermedite calculations.
Sure, I can easily implement my own functions, but then I have to explicitly say "mod n" for each operation. Instead one could build an numeric expression tree and defer actual calculations, and in the end state modulo n only once. (see my code below)
I started on this to clearly show what I mean, but I wonder if there already exists implementations of this, it seems quite useful so somebody ought to have implemented it.
module Modulo where
data Expr =
V Integer
| Plus Expr Expr
| Mult Expr Expr
deriving (Eq, Show)
instance Num Expr where
(+) = Plus
(*) = Mult
fromInteger = V
eval :: Integer -> Expr -> Integer
eval m (V i) = i `mod` m
eval m (Plus e1 e2) = (eval m e1 + eval m e2) `mod` m
eval m (Mult e1 e2) = (eval m e1 * eval m e2) `mod` m
fifteen :: Expr
fifteen = 10 + 5
test = eval 13 fifteen
Oleg did something of this kind, where you make an instance for modulo arithmetic, but for a arbitrary modulus. Implicit configurations.