给出以下代码:
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)))
我如何制作一个从示例中显示7 + 4 *(sqrt(x))+ e ^ y的函数?
答案 0 :(得分:2)
您要在此处实现的是showsPrec
类型类中的Show
函数。此函数使用一个额外的参数来指示操作的优先级,允许您更容易地实现理智的括号,并且它也更有效,因为它使用相当于差异列表来构建字符串(更有效的连接)。函数show
默认为\x -> showsPrec 0 x ""
,因此当您致电show
时,它将正常运行。你的案例的一个不完整的例子是
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 ")"
我会留给你实现其他构造函数(并测试它以确保没有错误,我不保证这是100%正确),但你应该有一个很好的开始。您可能希望尝试使用:i (*)
,:i (+)
和:i (**)
来确定我使用的优先级来自何处。
答案 1 :(得分:2)
正如我在对@ ThreeFx的回答中发表评论时,我认为使用Show
类型类进行漂亮打印或其他常规字符串修改是不好的做法。 Show
的文档指出,对于派生实例,“show
的结果是一个语法正确的Haskell表达式”由构造函数,常量等组成。这本身并不是一个规则,但它是一个非常有用的不变量。例如,当您在ghci中计算表达式时,您希望得到一个结果,然后您可以在代码中复制粘贴和重用。使用Show
执行您想要的操作会打破期望。
相反,我认为您应该公开一个函数 - 而不是show
- 您可以正确记录等,并且不会违反Show
实例上的隐式契约。 @Bakuriu在评论中提出了同样的建议。
该功能的实现几乎与@ThreeFx和@bheklilr提出的解决方案相同......只是没有instance
部分。这是我对@ bheklilr版本的再现:
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 ")"
请注意,我所做的只是机械地将showsPrec
重写为go
并将其包装在便利函数中。
现在Read
和Show
工作花花公子,和我们可以获得漂亮的印刷效果:
*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。我并不自称是任何权威;我相信很多人会像其他贡献者所建议的那样支持使用Show
。
答案 2 :(得分:0)
正如克里斯蒂安在他的评论中指出的那样,show
应该产生一个语法上有效的Haskell结构,这就是为什么重写show
不被认为是好的做法。你应该看看bheklilr的回答或Bakuriu对这个问题的评论。
然而,一种可能的方法是为每个构造函数手动实现Show
实例:
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
..
示例输出:
*Main> Sqrt (Var "x")
(sqrt(x))
*Main> Add (Sqrt (Const 4)) (Var "x")
(sqrt(4.0)) + x