Skip to content

Commit 811bcf0

Browse files
author
matteB10
committed
prop_readShow does not work
1 parent c8362cd commit 811bcf0

File tree

3 files changed

+181
-90
lines changed

3 files changed

+181
-90
lines changed

Labb4MB.hs

+179-58
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,222 @@
1+
module GraphCalc where
2+
13
import Test.QuickCheck
24
import Parsing
35
import Data.Maybe
46
import Data.Char
57
import Data.List
68
import Control.Monad
79

10+
11+
data Expr = Num Double
12+
| MonoOp MonoFunc Expr
13+
| BinOp BinFunc Expr Expr
14+
| Var
15+
deriving (Eq, Show)
16+
17+
data MonoFunc = Sin | Cos
18+
deriving (Eq, Show)
819

9-
data Expr = Num Double
10-
| Var Char
11-
| BinOp String (Double -> Double -> Double) Expr Expr
12-
| MonoOp String (Double -> Double) Expr
20+
data BinFunc = Add | Mul
21+
deriving (Eq, Show)
1322

1423

15-
instance Show Expr
16-
where show = showExpr
24+
--instance Show Expr
25+
-- where show = showExpr
26+
27+
instance Arbitrary Expr where
28+
arbitrary = sized arbExpr
1729

1830
showExpr :: Expr -> String
19-
showExpr (Num n) = show n
20-
showExpr (Var _) = "x"
21-
showExpr (MonoOp name _ expr) = name ++ " " ++ case expr of
22-
(Num n) -> showExpr expr
23-
(Var _) -> showExpr expr
24-
_ -> " (" ++ showExpr expr ++ ") "
25-
showExpr (BinOp name _ expr1 expr2) = case name of
26-
"*" -> showFactor expr1 ++ " " ++ name ++ " " ++ showFactor expr2
27-
"+" -> showExpr expr1 ++ " " ++ name ++ " " ++ showExpr expr2
28-
where
29-
showFactor (BinOp "+" _ expr1 expr2) = "(" ++ showExpr (add expr1 expr2) ++ ")"
30-
showFactor expr = showExpr expr
31+
showExpr (Num n) = show n
32+
showExpr Var = "x"
33+
showExpr (BinOp Mul e1 e2) = showFactor e1 ++ " * " ++ showFactor e2
34+
showExpr (BinOp Add e1 e2) = showExpr e1 ++ " + " ++ showExpr e2
35+
showExpr (MonoOp Sin e) = "sin " ++ showArg e
36+
showExpr (MonoOp Cos e) = "cos " ++ showArg e
37+
38+
showFactor (BinOp Add e1 e2) = "(" ++ showExpr (add e1 e2) ++ ")"
39+
showFactor e = showExpr e
40+
showArg (BinOp op e1 e2) = "(" ++ showExpr (BinOp op e1 e2) ++ ")"
41+
showArg e = showExpr e
42+
3143

3244
--------------------------------------------------------
3345

3446
x :: Expr
35-
x = Var 'x'
47+
x = Var
3648

3749
num :: Double -> Expr
3850
num d = Num d
3951

4052
add,mul :: Expr -> Expr -> Expr
41-
add x y = BinOp "+" (+) x y
42-
mul x y = BinOp "*" (*) x y
53+
add x y = BinOp Add x y
54+
mul x y = BinOp Mul x y
4355

4456
sin,cos :: Expr -> Expr
45-
sin x = MonoOp "sin" Prelude.sin x
46-
cos x = MonoOp "cos" Prelude.cos x
57+
sin x = MonoOp Sin x
58+
cos x = MonoOp Cos x
4759

4860
----------- TEST DATA ---------------------------
4961

50-
test = BinOp "+" (+) (Num 1) (Num 2) -- = 3
51-
testf = MonoOp "sin" Prelude.sin (Num 0) -- = 0
52-
test2 = MonoOp "sin" Prelude.sin test -- = sin(3) ca 0.14
62+
test = BinOp Add (Num 1) (Num 2) -- = 3
63+
testf = MonoOp Sin (Num 0) -- = 0
64+
test2 = MonoOp Sin test -- = sin(3) ca 0.14
65+
66+
test3 = mul (add (Num 1) (Num 2)) (add (Num 3) (Num 5)) -- = 3 * 8 = 24
67+
test4 = add (add (Num 1) (Num 2)) (add (Num 3) (Num 5)) -- = 3 + 8 = 11
68+
test5 = mul (mul (Num 1) (Num 2)) (mul (Num 3) (Num 5)) -- = 1*2 * 3*5 = 2 * 15 = 30
5369

54-
test3 = mul (add (Num 1) (Num 2)) (add (Num 3) (Num 5)) -- = 3 * 8 = 24
55-
test4 = add (add (Num 1) (Num 2)) (add (Num 3) (Num 5)) -- = 3 + 8 = 11
56-
test5 = mul (mul (Num 1) (Num 2)) (mul (Num 3) (Num 5)) -- = 1*2 * 3*5 = 2 * 15 = 30
70+
test6 = mul (mul (Var) (Num 2)) (mul (Num 3) (Num 5)) -- = 1*2 * 3*5 = 2 * 15 = 30
5771

58-
test6 = mul (mul (Var 'x') (Num 2)) (mul (Num 3) (Num 5)) -- = 1*2 * 3*5 = 2 * 15 = 30
72+
qFail = MonoOp Cos (MonoOp Cos (BinOp Mul Var (Num (-4.087662660418292))))
73+
failt = BinOp Mul (MonoOp Cos (BinOp Mul Var (Num 1))) (Num 2)
5974

6075
--------------------------------------------------
6176

6277
-- | Evaluates a given expression, where the second argument is the value of x
6378
eval :: Expr -> Double -> Double
64-
eval (Var _) x = x
79+
eval Var x = x
6580
eval (Num n) _ = n
66-
eval (BinOp _ op i j) x = (eval i x) `op` (eval j x)
67-
eval (MonoOp _ op i) x = op (eval i x)
81+
eval (BinOp Add i j) x = (eval i x) + (eval j x)
82+
eval (BinOp Mul i j) x = (eval i x) * (eval j x)
83+
eval (MonoOp Cos i) x = Prelude.cos (eval i x)
84+
eval (MonoOp Sin i) x = Prelude.sin (eval i x)
6885

6986
-- | Tries to read a expression from a string
7087
readExpr :: String -> Maybe Expr
71-
readExpr s = undefined
72-
73-
{-}
74-
do
75-
let s' = filter (not . isSpace) s
76-
77-
-}
78-
88+
readExpr s = case parse expr s' of
89+
Just(ex,"") -> return ex
90+
_ -> Nothing
91+
where s' = filter(not . isSpace) s
92+
93+
94+
assoc :: Expr -> Expr
95+
assoc (BinOp Add e1 (BinOp Add e2 e3)) = assoc (add (add (assoc e1) (assoc e2)) (assoc e3))
96+
assoc (BinOp Add e1 e2) = add (assoc e1) (assoc e2)
97+
assoc (BinOp Mul (BinOp Mul e1 e2) e3) = assoc (mul (mul (assoc e1) (assoc e2)) (assoc e3))
98+
assoc (BinOp Mul e1 e2) = mul (assoc e1) (assoc e2)
99+
assoc (MonoOp op e) = MonoOp op (assoc e)
100+
assoc (Num n) = Num n
101+
assoc Var = Var
102+
103+
-------------PARSERS------------------------
79104
-- | Parse a number
80-
number :: Parser Double
81-
number = read <$> oneOrMore digit
105+
number :: Parser Expr
106+
number = Num <$> readsP
82107

83108
-- | Parse an x-variable
84-
xparse :: Parser Char
85-
xparse = char 'x'
86-
109+
variable :: Parser Expr
110+
variable = char 'x' *> return Var
111+
112+
-- | Parse the sin function
113+
sinparse :: Parser Expr
114+
sinparse = do f <- funcparse 's' 'i' 'n' Sin
115+
e <- factor
116+
return (MonoOp f e)
117+
-- | Parse the cos function
118+
cosparse :: Parser Expr
119+
cosparse = do f <- funcparse 'c' 'o' 's' Cos
120+
e <- factor
121+
return (MonoOp f e)
122+
123+
-- | Simple parser for a three letter function
124+
funcparse a b c f = do c1 <- char a
125+
c2 <- char b
126+
c3 <- char c
127+
return f
128+
cosine :: Parser Expr
129+
cosine = ((MonoOp Cos) <$> k)
130+
where k = (char 'c') *> (char 'o') *> (char 's') *> factor
131+
132+
sine :: Parser Expr
133+
sine = ((MonoOp Sin) <$> k)
134+
where k = char 's' *> char 'i' *> char 'n' *> factor
135+
136+
-- | Parses expressions
87137
expr, term, factor :: Parser Expr
88138
expr = foldl1 add <$> chain term (char '+')
89-
term = foldl1 mul <$> chain factor (char '*')
90-
factor = Num <$> number <|> (Var <$> xparse <|> char '(' *> expr <* char ')')
91-
92-
93-
139+
term = foldl1 mul <$> chain factor (char '*')
140+
factor = number <|> variable <|> char '(' *> expr <* char ')' <|> sinparse <|> cosparse
141+
142+
-- | Test that showExpr and readExpr produces the same result
143+
prop_ShowReadExpr :: Expr -> Bool
144+
prop_ShowReadExpr e = (assoc $ fromJust $ readExpr (showExpr e)) == assoc e
145+
146+
-- | Generator for arbitrary expressions
147+
arbExpr :: Int -> Gen Expr
148+
arbExpr n = frequency [(1,rNum),(1,rVar),(n,rBin),(n,rMon)]
149+
where
150+
range = 5
151+
rVar = return Var
152+
rNum = Num <$> choose (-range,range)
153+
rBin = do
154+
let n' = n `div` 2
155+
op <- oneof [return add, return mul]
156+
e1 <- arbExpr n'
157+
e2 <- arbExpr n'
158+
return $ op e1 e2
159+
rMon = do
160+
op <- oneof [return GraphCalc.sin, return GraphCalc.cos]
161+
e <- arbExpr (n-1)
162+
return $ op e
163+
164+
-- | Simplifies expressions
165+
simplify :: Expr -> Expr
166+
simplify (Num n) = Num n
167+
simplify (Var) = Var
168+
simplify (BinOp Add x y) = simplifyAdd (simplify x) (simplify y)
169+
simplify (BinOp Mul x y) = simplifyMul (simplify x) (simplify y)
170+
simplify (MonoOp f x) = simplifyFunc f (simplify x)
171+
172+
-- | Simplifies multiplication expressions
173+
simplifyMul :: Expr -> Expr -> Expr
174+
simplifyMul (Num 0) e = Num 0
175+
simplifyMul e (Num 0) = Num 0
176+
simplifyMul e (Num 1) = e
177+
simplifyMul (Num 1) e = e
178+
simplifyMul x y = mul (simplify x) (simplify y)
179+
180+
-- | Simplifies add expressions
181+
simplifyAdd :: Expr -> Expr -> Expr
182+
simplifyAdd e (Num 0) = simplify e
183+
simplifyAdd (Num 0) e = simplify e
184+
simplifyAdd x y = add (simplify x) (simplify y)
185+
186+
-- | Simplifies sin and cos expressions
187+
simplifyFunc :: MonoFunc -> Expr -> Expr
188+
simplifyFunc Sin (Num x) | x == 0 || x == pi = Num 0
189+
| x == (pi/2) = Num 1
190+
simplifyFunc Sin e = MonoOp Sin (simplify e)
191+
simplifyFunc Cos (Num x) | x == 0 || x == pi = Num 1
192+
| x == (pi/2) = Num 0
193+
simplifyFunc Cos e = MonoOp Cos (simplify e)
194+
195+
-- | Test that a simplified expression returns correct result
196+
prop_Simplify :: Expr -> Bool
197+
prop_Simplify e = (eval e 0) == (eval (simplify e) 0)
198+
199+
-- | Differentiates an expression with regard to x
200+
differentiate :: Expr -> Expr
201+
differentiate (Num _) = Num 0
202+
differentiate (Var) = Num 1
203+
differentiate (BinOp Mul Var Var) = simplify $ mul (Num 2) Var
204+
differentiate (BinOp Mul e1 e2) = simplify $ add (mul (differentiate e1) e2) (mul e1 (differentiate e2))
205+
differentiate (BinOp Add e1 e2) = simplify $ add (differentiate e1) (differentiate e2)
206+
differentiate (MonoOp Sin e) = simplify $ mul (differentiate e) (MonoOp Cos e)
207+
differentiate (MonoOp Cos e) = simplify $ mul (Num (-1)) (mul (differentiate e) (MonoOp Sin e))
208+
209+
210+
211+
212+
213+
-----------MAIN-----------------------------
94214
main = do putStrLn "Welcome to the simple calculator!"
95-
readEvalPrint = do
96-
putStr "What would you like to calculate?"
97-
s <- getLine
98-
let s' = filter (not . isSpace) s
99-
case parse expr s' of
100-
Just (e, "") -> print $ eval e 1
101-
Nothing -> putStrLn "Invalid Expression!"
215+
forever readEvalPrint
216+
217+
readEvalPrint = do putStr "Expression? "
218+
s <- getLine
219+
case parse expr s of
220+
Just (e,"") -> do putStr "Value: "
221+
print (eval e 0)
222+
_ -> putStrLn "Syntax error!"

ParsingMB.hs renamed to Parsing.hs

+1-31
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module Parsing
1616
,parse
1717
-- * Basic parsers
1818
,sat,item,digit
19-
,readsP -- behaves as reads :: Read a => [(a,String)]
19+
,readsP -- behaves as reads :: Read => [(a,String)]
2020
, char, failure
2121
-- * Combining parsers
2222
,oneOrMore,zeroOrMore,chain,(<:>)
@@ -33,37 +33,7 @@ module Parsing
3333
, return
3434
)
3535

36-
<<<<<<< HEAD:ParsingMB.hs
37-
{----------------------
38-
39-
Aim: reusable Parser combinators including
40-
a new type for the Parser,
41-
but no export of the constructor
42-
43-
Changes (v3 2016) Thomas Hallgren
44-
Export <* and *> from class Applicative instead of the combinators <-< and >->
45-
Export <|> from class Alternative instead of +++
46-
47-
Changes (v2 2015)
48-
For compatibility with GHC>=7.10 Parser
49-
is now also instance Applicative
50-
51-
Removal: Class Functor, Applicative and Monad provide a number of
52-
functions that were previously exported explicitly, in particular
53-
(>*>) is available as the bind operation (>>=),
54-
success is return, pmap is fmap.
55-
56-
Additional function:
57-
readsP :: Read a => Parser a
58-
-- satisfies
59-
-- parse readsP s == listToMaybe (reads s)
60-
61-
----------------------}
62-
=======
63-
64-
>>>>>>> 0d3b2453122b330de7594a8a1c229e5b55a35fb9:Parsing.hs
6536
where
66-
6737
import Data.Char
6838
import Data.Maybe(listToMaybe)
6939
-- boilerplate for GHC 10.7 compatibility:

ParsingExamples.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ module ParsingExamples where
165165
expr, term, factor :: Parser Expr
166166
expr = leftAssoc Add term (char '+')
167167
term = leftAssoc Mul factor (char '*')
168-
factor = (Num <$> number) <|> (char '(' *> expr <* char ')')
168+
factor = (Num <$> number) <|> <|> (char '(' *> expr <* char ')')
169169

170170

171171

0 commit comments

Comments
 (0)