data Expr = Var Char | Not Expr | And Expr Expr | Or Expr Expr deriving (Eq, Ord)
instance Show Expr where
show (Var x) = [x]
show (Not (Var y)) = "~"++ show (Var y)
show (And (Var x) (Var y)) = show (Var x) ++ " ^ " ++ show (Var y)
show ((Or (Var x) (Var y))) = show (Var x) ++ " v " ++ show (Var y)
show (Not (Or (Var x) (Var y))) = "~(" ++ show (Or (Var x) (Var y)) ++ ")"
show (And (Var x) (And (Var y) (Var z))) = show (Var x) ++ " ^ " ++ "(" ++ show (And (Var y) (Var z)) ++ ")"
I`m not sure exactly why i get this error when i run:
>(Not (Not (Var 'a')))
*** Exception: (21,5)-(26,112): Non-exhaustive patterns in function show
Can anyone help me.
An And can also contain another And, so for example And (And (Var 'x') (Var 'y')) (Var 'z'). In your Show instance you always assume that the parameters are Vars, that is not necessary.
You can implement the Show instance as:
instance Show Expr where
show (Var x) = [x]
show (Not x) = "~ ("++ show x ++ ")"
show (And x y) = "(" ++ show x ++ " ^ " ++ show y ++ ")"
show (Or x y) = "(" ++ show x ++ " v " ++ show y ++ ")"
This will introduce a lot of parenthesis. Therefore it is better to work with a precedence parameter. In fact the Show instance already has support for this: you can work with showsPrec :: Int -> a -> String -> String. Here the Int parameter is the operator precedence of the outer context, and the first String parameter is the string that needs to be appended at the end: that is done for performance reasons.
We thus can implement this as:
instance Show Expr where
showsPrec n (Var x) = (x :)
showsPrec n (Not x) = showParen (n > 9) ( ('~' :) . showsPrec 10 x)
showsPrec n (And x y) = showParen (n > 8) ((showsPrec 9 x) . (" ^ " ++) . showsPrec 9 y)
showsPrec n (Or x y) = showParen (n > 7) ((showsPrec 8 x) . (" v " ++) . showsPrec 8 y)
Here we will show parenthesis for not if the outer countext has a precedence higher than 9, and call the showPrec with a precence 10 such that the showPrec inside will not print extra parenthesis, unless it has a precedence of 10 or higher. The same applies for the other functions.
This thus means that we can print an expression with parenthesis like:
ghci> show (Not (And (Or (Not (Var 'x')) (Var 'y')) (Var 'z')))
"~((~x v y) ^ z)"
Here the And … … will thus print parenthesis since it is called with a precedence of nine, and the threshold is 8 to print parenthesis. But there are no brackets for around ~x, since the threshold is lower than 10.
Instead of hard-coding lots of deep expressions, you should just pattern match on the topmost constructors and then recurse down.
instance Show Expr where
show (Var v) = [v]
show (Not x) = "Not ("++show x++")"
show (And x y) = "(" ++ show x ++ ") ∧ (" ++ ...
show (Or x y) = ...
Remember to implement the ∧ and ∨ operators if you mention them in the show results.
infixr 3 ∧
(∧) :: Expr -> Expr -> Expr
(∧) = And
Actually it is preferred to not implement show when defining recursive-data Show instances, instead implement showsPrec which has a more sophisticated way of adding parentheses as needed.
Related
I have a data type and function like this:
data Expr = Num Int | Add Expr Expr | Mult Expr Expr | Neg Expr | If Expr Expr Expr deriving (Show, Read)
prettyPrint :: Expr -> IO ()
prettyPrint expr = prettyPrint' expr 0
prettyPrint' :: Expr -> Int -> IO ()
prettyPrint' (Num x) i = putStrLn $ concat (replicate i " ") ++ "Num " ++ show x
prettyPrint' (Add x y) i = do
putStrLn $ concat (replicate i " ") ++ "Add"
prettyPrint' x (i+1)
prettyPrint' y (i+1)
prettyPrint' (Mult x y) i = do
putStrLn $ concat (replicate i " ") ++ "Mult"
prettyPrint' x (i+1)
prettyPrint' y (i+1)
prettyPrint' (Neg x) i = do
putStrLn $ concat (replicate i " ") ++ "Neg"
prettyPrint' x (i+1)
prettyPrint' (If x y z) i = do
putStrLn $ concat (replicate i " ") ++ "If"
prettyPrint' x (i+1)
prettyPrint' y (i+1)
prettyPrint' z (i+1)
In the function I am using pattern matching. The problem is that their is a lot of reuse of code. For example, the case for Mult and Add is basically the same code. Same goes for Num and Neg. Is there a way to write this based on how many variables the expression have? Like one for Num and Neg, since they have only one variable. One case for Mult and Add, since they have two variables. And a last case for If, since that expression have three variables.
NOTE:
I landed on this answer, I think it's a better solution than I started with:
prettyPrint :: Expr -> IO ()
prettyPrint expr = putStrLn (prettyPrint' 1 expr)
prettyPrint' :: Int -> Expr -> String
prettyPrint' i (Num x) = "Num " ++ show x
prettyPrint' i expr =
let indent x = concat (replicate i " ") ++ x
(op, args) = case expr of
Add x y -> ("Add", [x,y])
Mult x y -> ("Mult", [x,y])
Neg x -> ("Neg", [x])
If x y z -> ("If", [x,y,z])
in intercalate "\n" (op : map (indent . prettyPrint' (i + 1)) args)
First, I would stay out of the IO monad for as long as possible. Have prettyPrint' return a string to be printed.
prettyPrint :: Expr -> IO ()
prettyPrint = putStrLn . prettyPrint'
Now, the only job of prettyPrint' is to create a (possibly multiline) string to be printed. For numbers, that's easy: just use the show instance.
prettyPrint' :: Expr -> String
prettyPrint' e#(Num _) = show e
-- or, ignoring the Show instance for Expr altogether
-- prettyPrint' (Num x) = "Num " ++ show x
For the rest, there is a pattern:
Identify the constructor
Identify its arguments
Join the constructor name and its pretty-printed arguments with newlines. Each argument will be indented one level relative to its operator; the recursion will take care of multiple levels of indentation.
That will look like
prettyPrint' expr = let indent x = " " ++ x
(op, args) = case expr of
Add x y -> ("Add", [x,y])
Mult x y -> ("Mult", [x,y])
Neg x -> ("Neg", [x])
If x y z -> ("If", [x,y,z])
in intercalate "\n" (op : map (indent . prettyPrint') args)
As an example, consider what prettyPrint' will do with the expression Add (Num 3) (Num 5). First, it sets op to "Add" and args to [Num 3, Num 5]. Next, it maps indent . prettyPrint' over the argument list, to get [" Num 3", " Num 5"]. Putting the operator on the front of the list yields ["Add", " Num 3", " Num 3"], then joining them with intercalate produces "Add\n Num 3\n Num 5".
The only remaining boilerplate is in the case expression. I think it's possible to eliminate that, but it requires a level of generic programming I'm not familiar with. I'm sure someone else could probably run with my answer to fix that.
In general, when addressing duplication in code, it pays to keep the rule of three in mind. Two occurrences of a block of code isn't necessarily a problem.
That said, Haskell is a (very) strongly-typed language, so you generally can't pattern-match on arity like you can in, say, Erlang or Clojure.
If you really want to abstract away the recursion part of a recursive data structure, you can define the catamorphism for it. People often also call this a fold, so let's keep that slightly more friendly name:
data Expr =
Num Int | Add Expr Expr | Mult Expr Expr | Neg Expr | If Bool Expr Expr deriving (Show, Read)
foldExpr ::
(Int -> a) -> (a -> a -> a) -> (a -> a -> a) -> (a -> a) -> (Bool -> a -> a -> a) -> Expr -> a
foldExpr num _ _ _ _ (Num x) = num x
foldExpr num add mul neg iff (Add x y) =
add (foldExpr num add mul neg iff x) (foldExpr num add mul neg iff y)
foldExpr num add mul neg iff (Mult x y) =
mul (foldExpr num add mul neg iff x) (foldExpr num add mul neg iff y)
foldExpr num add mul neg iff (Neg x) = neg (foldExpr num add mul neg iff x)
foldExpr num add mul neg iff (If b x y) =
iff b (foldExpr num add mul neg iff x) (foldExpr num add mul neg iff y)
This is an entirely generic function that enables you turn turn any Expr value into any value of the type a, without worrying about reimplementing recursion every time. You just have to supply functions that deal with each of the cases.
You can, for example, easily write an evaluator:
evaluate :: Expr -> Int
evaluate = foldExpr id (+) (*) negate (\p x y -> if p then x else y)
(Notice, BTW, that I changed the definition of If, because I couldn't see how the OP definition would work.)
You can also write a function to turn an Expr value into a string, although this one is just a sketch; it needs indentation or bracket logic to work correctly:
prettyPrint :: Expr -> String
prettyPrint =
foldExpr
show -- Num
(\x y -> x ++ "+" ++ y) -- Add
(\x y -> x ++ "*" ++ y) -- Mult
(\x -> "(-" ++ x ++ ")") -- Neg
(\p x y -> "if " ++ show p ++ " then " ++ x ++ " else " ++ y) -- If
You can try it out in GHCi:
*Q53284410> evaluate (Num 42)
42
*Q53284410> evaluate (Add (Num 40) (Num 2))
42
*Q53284410> evaluate (Add (Mult (Num 4) (Num 10)) (Num 2))
42
*Q53284410> prettyPrint $ Num 42
"42"
*Q53284410> prettyPrint $ Mult (Num 6) (Num 7)
"6*7"
*Q53284410> prettyPrint $ Add (Mult (Num 2) (Num 3)) (Num 7)
"2*3+7"
Yes, just create a function to print list of Expr:
import Control.Monad (forM_)
printExprList::[Expr]->Int->String->IO ()
printExprList exprs i desc = do
putStrLn $ concat (replicate i " ") ++ desc
forM_ (zip exprs [i..]) $ \(e, j)-> prettyPrint' e (j+1)
and then call it to print:
prettyPrint' :: Expr -> Int -> IO ()
prettyPrint' (Add x y) i = printExprList [x, y] i "Add"
prettyPrint' (Mult x y) i = printExprList [x, y] i "Mult"
prettyPrint' (Neg x) i = printExprList [x] i "Neg"
prettyPrint' (If x y z) i = printExprList [x, y, z] i "If"
prettyPrint' (Num x) i = putStrLn $ concat (replicate i " ")
++ "Num " ++ show x
I wrote this data type:
data Poly = Lit Integer |
Var |
Add Poly Poly |
Mul Poly Poly
I'd like to also write a function printPoly for it, that takes a Poly expression and returns it converted to string. This can be implemented by just creating a custom instance of show for data type Poly like so:
instance Show Poly where
show (Lit x) = show x
show (Var) = "x"
show (Add x y) = (show x) ++ " + " ++ (show y)
show (Mul x y) = (show x) ++ "*" ++ (show y)
Now if I pass an expression like
main = do
print (Add (Lit 1) $ Add (Var) $ Mul (Var) $ Mul Var Var)
It returns 1 + x + x*x*x. Which is what I want. However, I want this done from a function printPoly, like so:
printPoly::Poly->String
printPoly (Lit x) = show x
printPoly (Var) = "x"
printPoly (Add x y) = (show x) ++ " + " ++ (show y)
printPoly (Mul x y) = (show x) ++ "*" ++ (show y)
Where am I wrong in the way I wrote this function?
To answer your question as-asked, this is what you want to do.
printPoly :: Poly -> String
printPoly (Lit x) = show x
printPoly (Var) = "x"
printPoly (Add x y) = (printPoly x) ++ " + " ++ (printPoly y)
printPoly (Mul x y) = (printPoly x) ++ "*" ++ (printPoly y)
instance Show Poly where
show = printPoly
However, this has some obvious problems. Consider print (Mul (Lit 2) $ Add Var Var). This would print 2*x + x, which when following precedence rules is clearly not what was intended.
printPoly :: Poly -> String
printPoly (Lit x) = show x
printPoly (Var) = "x"
printPoly (Add x y) = (b x $ printPoly x) ++ " + " ++ (b y $ printPoly y)
where b (Add _ _) p = "(" ++ p ++ ")"
b _ p = p
printPoly (Mul x y) = (b x $ printPoly x) ++ " * " ++ (b y $ printPoly y)
where b (Mul _ _) p = "(" ++ p ++ ")"
b _ p = p
This will print out 2 * (x + x) which is the correct interpretation of the given AST. Further, you could simplify the whole thing a bit by using printf from Text.Printf
printPoly :: Poly -> String
printPoly (Lit x) = show x
printPoly (Var) = "x"
printPoly (Add x y) = printf "%s + %s" (b x $ printPoly x) (b y $ printPoly y)
where b (Add _ _) = printf "(%s)"
b _ = id
printPoly (Mul x y) = printf "%s * %s" (b x $ printPoly x) (b y $ printPoly y)
where b (Mul _ _) = printf "(%s)"
b _ = id
Of course, this is still doing a lot of linked-list traversal, munging together strings so it won't be very fast, but at least it's correct ;)
Given the following code:
data Exprs = Const Double
| Var String --in math we often use char
| Sqrt Exprs --we can take sqrt of anything
| IntPow Exprs Int--the easy case of exponents
| Exp Exprs --e^expr
| Ln Exprs --logarithms
| Mult Exprs Exprs--multiplication
| Add Exprs Exprs
| Neg Exprs
deriving (Show, Eq, Ord)
x = Var "x"
y = Var "y"
z = Var "z"
-- to multiply x and y we type in "Mult x y"
example = Add (Const 7) ( Mult (Const 4) (Add (Sqrt x) (Exp y)))
How would I make a function that displays 7 + 4 * (sqrt(x)) + e^y from example?
What you want to implement here is the showsPrec function in the Show typeclass. This function takes an extra argument that indicates the precedence of the operation, allowing you to more easily achieve sane parentheses, and it also is more efficient since it uses what amounts to a diff list for building the string (more efficient concatenation). The function show defaults to \x -> showsPrec 0 x "", so when you call show it will work properly. An incomplete example for your case would be
data Exprs
= Const Double
| Var String --in math we often use char
| Sqrt Exprs --we can take sqrt of anything
| IntPow Exprs Int--the easy case of exponents
| Exp Exprs --e^expr
| Ln Exprs --logarithms
| Mult Exprs Exprs--multiplication
| Add Exprs Exprs
| Neg Exprs
deriving (Eq, Ord)
instance Show Exprs where
showsPrec n (Const x) = showParen (n > 10) $ showsPrec 11 x
showsPrec n (Var var) = showParen (n > 10) $ showString var
showsPrec n (Add l r) = showParen (n > 6) $ showsPrec 7 l . showString "+" . showsPrec 7 r
showsPrec n (Mult l r) = showParen (n > 7) $ showsPrec 8 l . showString "*" . showsPrec 8 r
showsPrec n (Sqrt e) = showParen (n > 10) $ showString "sqrt(" . shows e . showString ")"
I'll leave it to you to implement the other constructors (and test it heavily to ensure there are no mistakes, I do not guarantee that this is 100% correct), but you should have a pretty good start here. You may want to experiment with :i (*), :i (+), and :i (**) to figure out where the precedences I've used have come from.
As I posted in a comment to #ThreeFx's answer, I think it's bad practice to use the Show typeclass for pretty-printing or other general string munging. The documentation for Show notes that, for derived instances, "The result of show is a syntactically correct Haskell expression" made of constructors, constants, etc. That's not a rule per se, but it's a very helpful invariant. When you evaluate an expression in ghci, for instance, you expect to get a result that you can then copy-paste and reuse in code. Using Show to perform the operation you want breaks that expectation.
Rather, I think you should expose a function--not show--that you can properly document, etc., and that doesn't violate the implicit contract on Show instances. #Bakuriu suggested as much in a comment.
The implementation of that function can be almost identical to the solutions #ThreeFx and #bheklilr proposed... just without the instance part. Here's my rendition of #bheklilr's version:
data Exprs
= Const Double
| Var String --in math we often use char
| Sqrt Exprs --we can take sqrt of anything
| IntPow Exprs Int--the easy case of exponents
| Exp Exprs --e^expr
| Ln Exprs --logarithms
| Mult Exprs Exprs--multiplication
| Add Exprs Exprs
| Neg Exprs
deriving (Eq, Ord, Show, Read)
prettyPrint :: Exprs -> String
prettyPrint e = go 0 e ""
where
go n (Const x) = showParen (n > 10) $ showsPrec 11 x
go n (Var var) = showParen (n > 10) $ showString var
go n (Add l r) = showParen (n > 6) $ go 7 l . showString "+" . go 7 r
go n (Mult l r) = showParen (n > 7) $ go 8 l . showString "*" . go 8 r
go n (Sqrt e) = showParen (n > 10) $ showString "sqrt(" . go n e . showString ")"
Note that all I've done is mechanically rewrite showsPrec as go and wrap it in a convenience function.
Now Read and Show work dandy, and we can get nice pretty-printing:
*SO26169469> Add (Const 7) ( Mult (Const 4) (Add (Sqrt (Var "x")) (Const 3)))
Add (Const 7.0) (Mult (Const 4.0) (Add (Sqrt (Var "x")) (Const 3.0)))
*SO26169469> show it
"Add (Const 7.0) (Mult (Const 4.0) (Add (Sqrt (Var \"x\")) (Const 3.0)))"
*SO26169469> read it :: Exprs
Add (Const 7.0) (Mult (Const 4.0) (Add (Sqrt (Var "x")) (Const 3.0)))
*SO26169469> prettyPrint it
"7.0+4.0*(sqrt(x)+3.0)"
P.S. I don't claim to be any authority; I'm sure many people would support using Show as the other contributors suggest.
Careful: Bad practice ahead!
As Christian pointed out in his comment, show should yield a syntactically valid Haskell construct, which is why overriding show is not considered good practice. You should hava a look at bheklilr's answer or Bakuriu's comments on the question.
Nevertheless, one possible way is to implement the Show instance manually for every constructor:
instance Show Exprs where
show (Const d) = show d
show (Var v) = v
show (Sqrt ex) = "(sqrt(" ++ show ex ++ "))"
..
show (Add e1 e2) = show e1 ++ " + " ++ show e2
..
Sample output:
*Main> Sqrt (Var "x")
(sqrt(x))
*Main> Add (Sqrt (Const 4)) (Var "x")
(sqrt(4.0)) + x
I am trying to write a show instance to display well formed formula but after miming whole syntax I am still facing the same error as below.
Hugs> :load "C:\\Users\\Devil\\Desktop\\CASESTUDY1.hs"
ERROR file:.\CASESTUDY1.hs:15 - Ambiguous variable occurrence "show"
*** Could refer to: CASESTUDY1.show Hugs.Prelude.show
Below is the content of my .hs file include data type and related show instance .
module CASESTUDY1
where
data Wff = VAR String
| NEG Wff
| AND Wff Wff
| OR Wff Wff
| IMPL Wff Wff
instance Show Wff where
show (VAR x) = x
show (NEG x) = "~" ++ show(x)
show (AND x y) = "(" ++ show(x) ++ "^" ++ show(y) ++ ")"
show (OR x y) = "(" ++ show(x) ++ "v" ++ show(y) ++ ")"
show (IMPL x y) = "(" ++ show(x) ++ "-->" ++ show(y) ++ ")"
In haskell, whitespace is important. You need to indent the show's that belong to your instance of Show.
instance Show Wff where
show (VAR x) = show x
show (NEG x) = "~" ++ show x
show (AND x y) = "(" ++ show x ++ "^" ++ show y ++ ")"
show (OR x y) = "(" ++ show x ++ "v" ++ show y ++ ")"
show (IMPL x y) = "(" ++ show x ++ "-->" ++ show y ++ ")"
Also, you do not need parenthesis to pass the parameters to show. show(x) should be show x.
If you are learning haskell I recommend these exceptional resources:
Learn You a Haskell For Great Good
Real World Haskell
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.