如何使函数实现Show的自定义实例的内部。哈斯克尔

时间:2014-10-27 15:44:55

标签: haskell

我写了这个数据类型:

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)

我写这个函数的方式在哪里错了?

1 个答案:

答案 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

当然,这仍然会进行大量的链表遍历,将字符串拼凑在一起所以它不会很快,但至少它是正确的;)