This is a simple code from my lecture notes. I dont understand it very well. Can anyone explain to me what is meaning of "case (eval e1, eval e2) of". From my understanding, this command should work for const Int. There is no line talk about eval e1->bool.
-- Simple expressions
--
data Expr = Const Int
| Add Expr Expr -- arguments must be Ints
| Equal Expr Expr -- arguments must be of same type
| If Expr Expr Expr -- 1st argument must be a Bool
-- Evaluation results
--
data Value = IntV Int
| BoolV Bool
deriving Show
-- Evaluate a simple expression.
--
eval :: Expr -> Value
eval (Const i) = IntV i
eval (Add e1 e2) =
case (eval e1, eval e2) of
(IntV i1, IntV i2) -> IntV $ i1 + i2
_ -> error "Add: Int expected"
eval (Equal e1 e2) =
case (eval e1, eval e2) of
(IntV i1, IntV i2) -> BoolV $ i1 == i2
(BoolV b1, BoolV b2) -> BoolV $ b1 == b2
_ -> error "Equal: same types expected"
eval (If ec et ee) =
case eval ec of
BoolV flag
| flag -> eval et
| otherwise -> eval ee
_ -> error "If: conditional must be Bool"
A case statement is a bit like a switch statement from other languages. The expression between the case and the of is matched against each pattern in order until one matches. The last case _ matches everything, a bit like a default case in a Java switch statement.
e.g.
-- simple data type which just wraps a value
data Foo a = Foo a
n = Foo 1
describe :: Foo Int -> String
describe n = case n of
Foo 0 -> "Zero"
Foo 1 -> "One"
Foo 2 -> "Two"
_ -> "Every other Foo Int!"
The example from your code combines two expressions in a tuple so they can be pattern matched at the same time:
case (eval e1, eval e2) of
(IntV i1, IntV i2) -> IntV $ i1 + i2
_ -> error "Add: Int expected"
It's convenient and shorter than matching both individually, which might look something like this:
case eval e1 of
IntV i1 -> case eval e2 of
IntV i2 -> IntV $ i1 + i2
_ -> error "Add: Int expected"
_ -> error "Add: Int expected"
Related
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
There's an exercise on this page of the Haskell Wikibook which gets you to work through a scenario using Maybe and Either (presumably to show that it is quite painful for the use case).
The exercise is:
data Expr = I Int
| B Bool -- boolean constants
| Add Expr Expr
| Mul Expr Expr
| Eq Expr Expr -- equality test
eval :: Expr -> Maybe (Either Int Bool)
-- Your implementation here.
The first lines of the solution are - I think - straightforward:
data Expr = I Int -- integer constants
| B Bool -- boolean constants
| Add Expr Expr -- add two expressions
| Mul Expr Expr -- multiply two expressions
| Eq Expr Expr -- equality test
deriving (Show)
eval :: Expr -> Maybe (Either Int Bool)
eval (I n) = Just $ Left n
eval (B b) = Just $ Right b
eval (Add e1 e2) = ...
eval (Mul e1 e2) = ...
eval (Eq e1 e2) = ...
But I'm not exactly sure how to define the rest. As an example I guess for add I need to unpack the fromLeft, fromJust of each expression, but I'm not sure how to do this properly (with pattern matching?)
Thanks in advance!
Yes, with pattern matching and perhaps even the Maybe monad.
You could implement the eval (Add e1 e2) branch using just pattern matching:
eval (Add e1 e2) = case eval e1 of
Just (Left i1) -> case eval e2 of
Just (Left i2) -> Just (Left (i1 + i2))
_ -> Nothing
_ -> Nothing
Pattern matching on a pair is one good way of reducing the amount of nested case statements:
eval (Add e1 e2) = case (eval e1, eval e2) of
(Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2))
_ -> Nothing
Or, you could use the Maybe monad as an abstraction over those case statements. It will automatically return Nothing if any of the pattern matching fails in the do block bindings (due to how the Maybe monad implements fail).
eval (Add e1 e2) = do
Left i1 <- eval e1
Left i2 <- eval e2
return (Left (i1 + i2))
eval (Add e1 e2) = ...
You will want to evaluate e1 and e2 then pattern match on those results. There's various ways of doing that. For instance you can use let bindings.
let ev1 = eval e1
ev2 = eval e2
in
And then pattern match using the case construction. Or with no let bindings if you prefer, you can just do
case (eval e1, eval e2) of
and pattern match on that pair.
I want to write a logical formulae solving program in Haskell. So far I've managed to print given formula as string, for example formula
(I (N (Z 'p')) (A (C (Z 'p') (Z 'q')) (Z 'r')))
results in
"(~p => ((p & q) | r))"
where I is implication, A is alternative, C in conjunction, N in negation and Z is character.
My data type is like:
data Formula = Z Char | V Bool | N Formula
| K Formula Formula | A Formula Formula
| C Formula Formula | Join Formula Formula
My problem is that I don't know how to write a function, which will evaluate formula with given map of characters and boolean values, I mean, for ex.:
[('p', True), ('q', False), ('r', False)]
I can't come up with a method to substitute those letters with some True/False value and check it. Is there any simple way to do this?
You can just pass the list of character and boolean values and use the lookup function from Data.List:
import Data.List
evaluate :: [(Char, Bool)] -> Formula -> Bool
evaluate mapping (Z sym) =
case lookup sym mapping of
Just v -> v
Nothing -> error $ "Undefined symbol " ++ show v
evaluate _mapping (V v) = v
evaluate mapping (N formula) = not (evaluate mapping formula)
...
For a more efficient representation of the mapping, use the Data.Map module instead of the list of associations.
You need to write an interpreter. This sounds scary, but Haskell actually makes it easy. You can make one like:
eval :: [(Char, Bool)] -> Formula -> Maybe Bool
eval vars (Z c) = lookup c vars
eval vars (V b) = Just b
eval vars (N expr) = fmap not $ eval vars expr
eval vars (A e1 e2) = liftM2 (||) (eval vars e1) (eval vars e2)
And just finish filling out the rest of the definitions for the different constructors in this style.
As Ganesh points out, you can also use the Data.Map module for a more efficient lookup, but the general concept remains. If you wanted it to look nice and pretty, you could also define a few operators like
(<||>) :: Monad m => m Bool -> m Bool -> m Bool
(<||>) = liftM2 (||)
(<&&>) :: Monad m => m Bool -> m Bool -> m Bool
(<&&>) = liftM2 (&&)
eval :: ...
-- ...
eval vars (A e1 e2) = eval vars e1 <||> eval vars e2
eval vars (C e1 e2) = eval vars e1 <&&> eval vars e2
And then your code will be very readable. Conveniently, these operators can be used in other situations, such as:
isABCD :: Char -> Bool
isABCD = (== 'A') <||> (== 'B') <||> (== 'C') <||> (== 'D')
Obviously, this is a very contrived example, but it has its uses
I am trying to write a program in Haskell to compute the denotational semantics of an imperative language program with integer variables, 1-dimensional (integer) arrays and functions. The function I am starting with is of the type:
progsem :: Prog -> State -> State
where State is the following:
type State (Name -> Int, Name -> Int -> Int)
The first part is the value of integer variables, while the second part is the value of an array variable at a particular index.
The program will have the following qualities:
progsem will return the resulting state after the program executes
functions have two parameter lists, one for integer variables, and one for array variables.
functions are call by value result
Here is the abstract syntax for the imperative language:
-- names (variables) are just strings.
type Name = String
-- a program is a series (list) of function definitions, followed by a
-- series of statements.
type Prog = ([FunDefn],[Stmt])
-- a statement is either...
data Stmt =
Assign Name Exp -- ...assignment (<name> := <exp>;)
| If BExp [Stmt] [Stmt] -- ...if-then-else (if <bexp> { <stmt>* } else { <stmt>* })
| While BExp [Stmt] -- ...or a while-loop (while <bexp> { <stmt>*> })
| Let Name Exp [Stmt] -- ...let bindings (let <name>=<exp> in { <stmt> *})
| LetArray Name Exp Exp [Stmt] -- ...let-array binding (letarray <name> [ <exp> ] := <exp> in { <stmt>* })
| Case Exp [(Int,[Stmt])] -- ...case statements
| For Name Exp Exp [Stmt] -- ...for statements
| Return Exp -- ...return statement
| ArrayAssign Name Exp Exp -- ...or array assignment (<name> [ <exp> ] := <exp>;)
deriving Show
-- an integer expression is either...
data Exp =
Add Exp Exp -- ...addition (<exp> + <exp>)
| Sub Exp Exp -- ...subtract (<exp> - <exp>)
| Mul Exp Exp -- ...multiplication (<exp> * <exp>)
| Neg Exp -- ...negation (-<exp>)
| Var Name -- ...a variable (<name>)
| LitInt Int -- ...or an integer literal (e.g. 3, 0, 42, 1999)
| FunCall Name [Exp] [Name] -- ...or a function call (<name> (<exp>,...,<exp> [; <name>,...,<name>]))
| VarArray Name Exp -- ...or an array lookup (<name> [ <exp> ])
deriving Show
-- a boolean expression is either...
data BExp =
IsEq Exp Exp -- ...test for equality (<exp> == <exp>)
| IsNEq Exp Exp -- ...test for inequality (<exp> != <exp>)
| IsGT Exp Exp -- ...test for greater-than (<exp> > <exp>)
| IsLT Exp Exp -- ...test for less-than (<exp> < <exp>)
| IsGTE Exp Exp -- ...test for greater-or-equal (<exp> >= <exp>)
| IsLTE Exp Exp -- ...test for less-or-equal (<exp> <= <exp>)
| And BExp BExp -- ...boolean and (<bexp> && <bexp>)
| Or BExp BExp -- ...boolean or (<bexp> || <bexp>)
| Not BExp -- ...boolean negation (!<bexp>)
| LitBool Bool -- ... or a boolean literal (true or false)
deriving Show
type FunDefn = (Name,[Name],[Name],[Stmt])
Now, I do not have a specific question, but I was wondering if someone could point me in the right direction on how to go about writing the semantics.
In the past I have done something similar for an imperative programming language without arrays and functions. It looked something like this:
expsem :: Exp -> State -> Int
expsem (Add e1 e2) s = (expsem e1 s) + (expsem e2 s)
expsem (Sub e1 e2) s = (expsem e1 s) - (expsem e2 s)
expsem (Mul e1 e2) s = (expsem e1 s) * (expsem e2 s)
expsem (Neg e) s = -(expsem e s)
expsem (Var x) s = s x
expsem (LitInt m) _ = m
boolsem :: BExp -> State -> Bool
boolsem (IsEq e1 e2) s = expsem e1 s == expsem e2 s
boolsem (IsNEq e1 e2) s= not(expsem e1 s == expsem e2 s)
boolsem (IsGT e1 e2) s= expsem e1 s > expsem e2 s
boolsem (IsGTE e1 e2) s= expsem e1 s >= expsem e2 s
boolsem (IsLT e1 e2) s= expsem e1 s < expsem e2 s
boolsem (IsLTE e1 e2) s= expsem e1 s <= expsem e2 s
boolsem (And b1 b2) s= boolsem b1 s && boolsem b2 s
boolsem (Or b1 b2) s= boolsem b1 s || boolsem b2 s
boolsem (Not b) s= not (boolsem b s)
boolsem (LitBool x) _= x
stmtsem :: Stmt -> State -> State
stmtsem (Assign x e) s = (\z -> if (z==x) then expsem e s else s z)
stmtsem (If b pt pf) s = if (boolsem b s) then (progsem pt s) else (progsem pf s)
stmtsem (While b p) s = if (boolsem b s) then stmtsem (While b p) (progsem p s) else s
stmtsem (Let x e p) s = s1 where
initvalx = s x
letvalx = expsem e s
snew = progsem p (tweak s x letvalx)
s1 z = if (z == x) then initvalx else snew z
tweak :: State->Name->Int->State
tweak s vr n = \y -> if vr == y then n else s y
progsem :: Prog -> State -> State
progsem smlist s0 = (foldl (\s -> \sm -> (stmtsem sm s)) (s0) ) smlist
s :: State
s "x" = 10
Where states were of the type
type State= Name -> Int
Like I said, I do not need an in depth answer, but any help/hints/pointers would be much appreciated.
I'll deviate a bit from your given code and indicate how you might start to write a monadic interpreter which encodes the evaluation semantics for an toy imperative language, much like the one you specified. You'll need a frontend AST like you have:
import Control.Monad.State
import qualified Data.Map as Map
data Expr = Var Var
| App Expr Expr
| Fun Var Expr
| Lit Ground
| If Expr Expr Expr
-- Fill in the rest
deriving (Show, Eq, Ord)
data Ground = LInt Integer
| LBool Bool
deriving (Show, Eq, Ord)
We will evaluate via a function eval into concrete Value types.
data Value = VInt Integer
| VBool Bool
| VUnit
| VAddress Int
| VClosure String Expr TermEnv
type TermEnv = Map.Map String Value
type Memory = [Value]
type Interpreter t = State Memory t
eval :: TermEnv -> Expr -> State Memory Value
eval _ (Lit (LInt k)) = return $ VInt k
eval _ (Lit (LBool k)) = return $ VBool k
eval env (Fun x body) = return (VClosure x body env)
eval env (App fun arg) = do
VClosure x body clo <- eval env fun
res <- eval env fun
args <- eval env arg
let nenv = Map.insert x args clo
eval nenv body
eval env (Var x) = case (Map.lookup x env) of
Just v -> return v
Nothing -> error "prevent this statically!"
eval env (If cond tr fl) = do
VBool br <- eval env cond
if br == True
then eval env tr
else eval env fl
-- Finish with the rest of your syntax.
programs will return the resulting state after the program executes
To run the interpreter we need to feed it two values: the binding environment of variables and the values on the heap. This will return a tuple of the resulting value and the memory state which you can then feed back to the function itself if building a REPL-like loop.
runInterpreter :: TermEnv -> Memory -> Expr -> (Value, [Value])
runInterpreter env mem x = runState (eval env x) mem
initMem = []
initTermEnv = Map.empty
Since you're writing an imperative language likely you'll want to add state and references, so you can create new AST nodes working allocating and mutating Refs. Left for you to do is to add the logic for allocating an Array as a sequence of Refs and using pointer arithmetic when indexing and assigning into it.
data Expr = -- Same as above
| Ref Expr
| Access Expr
| Assign Expr Expr
eval :: TermEnv -> Expr -> State Memory Value
...
eval env (Ref e) = do
ev <- eval env e
alloc ev
eval env (Access a) = do
VAddress i <- eval env a
readAddr i
eval env (Assign a e) = do
VAddress i <- eval env a
ev <- eval env e
updateAddr ev i
With this we'll need some helper functions for dealing with the values on the heap which are just thin wrappers around the State monad functions.
access :: Int -> Memory -> Value
access i mem = mem !! i
update :: Int -> Value -> Memory -> Memory
update addr val mem = a ++ [val] ++ b
where
(a, _:b) = splitAt addr mem
alloc :: Value -> Interpreter Value
alloc val = do
mem <- get
put $ mem ++ [val]
return $ VAddress (length mem)
readAddr :: Int -> Interpreter Value
readAddr i = do
mem <- get
return $ access i mem
updateAddr :: Value -> Int -> Interpreter Value
updateAddr val i = do
mem <- get
put $ update i val mem
return VUnit
Hope that helps get you started.