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
Related
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.
I have a simple arithmetic expression data structure that I want to be able to print. For sake of simplicity here I have made an example with 3 binary operations, addition, multiplication and division. The definition looks like this:
module ExprPrint where
import Text.Printf
data Expr = Lit Int
| Add Expr Expr
| Mul Expr Expr
| Div Expr Expr
instance Show Expr where
show (Lit x) = show x
show (Add e1 e2) = printf "(%s) + (%s)" (show e1) (show e2)
show (Mul e1 e2) = printf "(%s) * (%s)" (show e1) (show e2)
show (Div e1 e2) = printf "(%s) / (%s)" (show e1) (show e2)
The goal I have is to print the data structure while removing all superfluous parenthesis. of course the naive show function I have implemented above includes way too many of them. So what I want to do is make the Show instance take the precedence (Div and Mul over Add) and associativity(Add and Mul are associative while Div is left-associative) of the operations into account.
Here are some examples:
one = Lit 1
-- Shows "((1) + (1)) + (1)" but should be 1 + 1 + 1
addAssoc = show $ Add (Add one one) one
-- Shows "((1) * (1)) * (1)" but should be 1 * 1 * 1
mulAssoc = show $ Mul (Mul one one) one
-- Shows "((1) / (1)) / (1)" but should be 1 / 1 / 1
divAssoc = show $ Div (Div one one) one
-- Shows "(1) / ((1) / (1)) but should be 1 / (1 / 1)
divAssoc2 = show $ Div one (Div one one)
-- Show "((1) * (1)) + (1)" but should 1 * 1 + 1
addPrec = show $ Add (Mul one one) one
-- Show "(1) + ((1) * (1))" but should show 1 + (1 * 1)
addPrec2 = show $ Add one (Mul one one)
Is there an "easy" to take that into account in the show instance? I think I could do it by taking all the cases into account but that would be an explosion of functions. Is there some algorithm or known way to handle this?
I hope somebody has some pointers!
Thanks.
An instance in terms of show isn't powerful enough to avoid redundant parentheses, since it doesn't have any information about precedence available. You'll need to write your instance in terms of showsPrec instead, which does, like this:
module ExprPrint where
import Text.Show
data Expr = Lit Int
| Add Expr Expr
| Mul Expr Expr
| Div Expr Expr
instance Show Expr where
showsPrec prec (Lit x) = showsPrec prec x
showsPrec prec (Add e1 e2) = showParen (prec >= 7) $ showsPrec 7 e1 . showString " + " . showsPrec 7 e2
showsPrec prec (Mul e1 e2) = showParen (prec >= 8) $ showsPrec 8 e1 . showString " * " . showsPrec 8 e2
showsPrec prec (Div e1 e2) = showParen (prec >= 8) $ showsPrec 8 e1 . showString " / " . showsPrec 8 e2
I chose 6 and 7 for your precedence levels since that's what Haskell uses for its own +, *, and div operators, but it should be obvious how you'd choose different ones.
As for associativity, there's no perfect way to do that in general, but you can fake it with some precedence tweaks in your case, since math doesn't have any operators at the same precedence levels with different associativies. Here's an example of how to do that (I added Exp, with precendence level 8, to give an example of the right-associative way to do it too):
module ExprPrint where
import Text.Show
data Expr = Lit Int
| Add Expr Expr
| Mul Expr Expr
| Div Expr Expr
| Exp Expr Expr
instance Show Expr where
showsPrec prec (Lit x) = showsPrec prec x
showsPrec prec (Add e1 e2) = showParen (prec >= 7) $ showsPrec 6 e1 . showString " + " . showsPrec 7 e2
showsPrec prec (Mul e1 e2) = showParen (prec >= 8) $ showsPrec 7 e1 . showString " * " . showsPrec 8 e2
showsPrec prec (Div e1 e2) = showParen (prec >= 8) $ showsPrec 7 e1 . showString " / " . showsPrec 8 e2
showsPrec prec (Exp e1 e2) = showParen (prec >= 9) $ showsPrec 9 e1 . showString " ^ " . showsPrec 8 e2
That's still not perfect, since it still doesn't know the associative property of Add or Mul, so Mul one (Mul one one) will show as 1 * (1 * 1) instead of 1 * 1 * 1, but I don't think there's any possible way to fix that, since division doesn't share that property, but since it has the same precedence as multiplication, you can't distinguish them in showsPrec.
Actually, you can cheat a bit more than that, by peeking at the next level down and re-associating:
module ExprPrint where
import Text.Show
data Expr = Lit Int
| Add Expr Expr
| Mul Expr Expr
| Div Expr Expr
| Exp Expr Expr
instance Show Expr where
showsPrec prec (Lit x) = showsPrec prec x
showsPrec prec (Add e1 (Add e2 e3)) = showsPrec prec (Add (Add e1 e2) e3)
showsPrec prec (Add e1 e2) = showParen (prec >= 7) $ showsPrec 6 e1 . showString " + " . showsPrec 7 e2
showsPrec prec (Mul e1 (Mul e2 e3)) = showsPrec prec (Mul (Mul e1 e2) e3)
showsPrec prec (Mul e1 e2) = showParen (prec >= 8) $ showsPrec 7 e1 . showString " * " . showsPrec 8 e2
showsPrec prec (Div e1 e2) = showParen (prec >= 8) $ showsPrec 7 e1 . showString " / " . showsPrec 8 e2
showsPrec prec (Exp e1 e2) = showParen (prec >= 9) $ showsPrec 9 e1 . showString " ^ " . showsPrec 8 e2
I think this is perfect. All of your test cases pass now.
This question already has answers here:
Haskell ranges and floats
(2 answers)
Is floating point math broken?
(31 answers)
Closed 4 years ago.
If i want to generate a list with the input:
[3.1,5.1..8.1]
GHC 8.6.3 returns:
[3.1,5.1,7.1,9.099999999999998]
My problem here isn't the approximation of 9.1, but why the list made by GHC has one element more than the following solution.
In the documentation I found in GHC.Enum, that enumFromThenTo translates this to something similar to the following:
-- | Used in Haskell's translation of #[n,n'..m]# with
-- #[n,n'..m] = enumFromThenTo n n' m#, a possible implementation
-- being #enumFromThenTo n n' m = worker (f x) (c x) n m#,
-- #x = fromEnum n' - fromEnum n#, #c x = bool (>=) (<=) (x > 0)#
-- #f n y
-- | n > 0 = f (n - 1) (succ y)
-- | n < 0 = f (n + 1) (pred y)
-- | otherwise = y# and
-- #worker s c v m
-- | c v m = v : worker s c (s v) m
-- | otherwise = []#
So the following code:
import Data.Bool
eftt n s m = worker (f x) (c x) n m
where x = (fromEnum s) - (fromEnum n)
c x = bool (>=) (<=) (x > 0)
f n y
| n > 0 = f (n-1) (succ y)
| n < 0 = f (n+1) (pred y)
| otherwise = y
worker s c v m
| c v m = v: worker s c (s v) m
| otherwise = []
On the same input as before, this however returns this list:
[3.1,5.1,7.1]
The real implementation defined in GHC.Enum is the following:
enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
But there is no instantiation of Enum Double or Enum Float in GHC.Enum
So when I tried to reproduce this with the following code:
import Prelude(putStrLn,show)
import GHC.Enum(toEnum,fromEnum,Enum,enumFromThenTo)
import GHC.Base(map)
main = putStrLn (show (_enumFromThenTo 3.1 5.1 8.1))
_enumFromThenTo :: (Enum a) => a -> a -> a -> [a]
_enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
I compiled with:
$ ghc -package ghc -package base <file.hs>
The result was again:
[3.0,5.0,7.0]
What is happening here, such that the output becomes:
[3.1,5.1,7.1,9.099999999999998]
?
Well, this is instance Enum Double
instance Enum Double where
enumFromThenTo = numericEnumThenFromTo
The implementation is here
numericEnumFromThenTo :: (Ord a, Fractional a) => a -> a -> a -> [a]
numericEnumFromThenTo e1 e2 e3
= takeWhile predicate (numericEnumFromThen e1 e2)
where
mid = (e2 - e1) / 2
predicate | e2 >= e1 = (<= e3 + mid)
| otherwise = (>= e3 + mid)
More important than the implementation is the note above it:
-- These 'numeric' enumerations come straight from the Report
Which refers to this passage in the (2010) Report:
For Float and Double, the semantics of the enumFrom family is given by the rules for Int above, except that the list terminates when the elements become greater than e3 + i∕2 for positive increment i, or when they become less than e3 + i∕2 for negative i.
(Where e3 refers to the upper bound, and i the increment.)
The comment you found on Enum and the implementation in class Enum are both irrelevant. The comment is just example code detailing how an instance might be implemented, and the implementation given is inside a class, and thus may be overridden with anything.
ghci> show (Left 3)
"Left 3"
ghci> show (Just 0)
"Just 0"
ghci> show (Just (Left 3))
"Just (Left 3)"
How does Haskell automatically put parentheses around nested constructor arguments?
showsPrec :: Int -> a -> ShowS is the function used internally by show to consistently put parentheses around a term.
The Int parameter indicate the precedence of the outer context. If the precedence of the current constructor is greater than the precedence of the context, showParen :: Bool -> ShowS -> ShowS puts parentheses around the constructor. Here an example for a very basic AST :
data Exp = Exp :+: Exp
| Exp :*: Exp
-- The precedence of operators in haskell should match with the AST shown
infixl 6 :+:
infixl 7 :*:
mul_prec, add_prec :: Int
mul_prec = 7
add_prec = 6
instance Show Exp where
showsPrec p (x :+: y) = showParen (p > add_prec) $ showsPrec (add_prec+1) x
. showString " :+: "
. showsPrec (add_prec+1) y
showsPrec p (x :*: y) = showParen (p > mul_prec) $ showsPrec (mul_prec+1) x
. showString " :*: "
. showsPrec (mul_prec+1) y
show t = showsPrec 0 t "" -- Default definition
showsPrec, showString, showParen, etc, act on difference lists (ShowS = String -> String), where the argument is a string appended to the result. Concatenation is done by composition, and conversion to String by application with an empty string.
The show implementation use showsPrec with the lowest precedence, the expression to print, and finally, the end of the string [].
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.