我写了这个数据类型:
data Poly = Lit Integer |
Var |
Add Poly Poly |
Mul Poly Poly
我还想为它编写一个函数printPoly,它接受一个Poly表达式并将其转换为字符串。这可以通过为数据类型Poly创建show的自定义实例来实现,如下所示:
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)
现在,如果我传递一个像
这样的表达式main = do
print (Add (Lit 1) $ Add (Var) $ Mul (Var) $ Mul Var Var)
返回1 + x + x*x*x
。这就是我想要的。但是,我希望通过函数printPoly完成此操作,如下所示:
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)
我写这个函数的方式在哪里错了?
答案 0 :(得分:1)
要回答你提出的问题,这就是你想要做的。
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
然而,这有一些明显的问题。考虑print (Mul (Lit 2) $ Add Var Var)
。这将打印2*x + x
,当遵循优先规则时,显然不符合预期。
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
这将打印出2 * (x + x)
,这是对给定AST的正确解释。此外,您可以使用printf
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
当然,这仍然会进行大量的链表遍历,将字符串拼凑在一起所以它不会很快,但至少它是正确的;)