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.