Haskell显示Tree没有Data.Tree或派生(显示)

时间:2016-03-01 20:51:12

标签: haskell

大家好我的实例在Haskell中显示一个树有问题:这是我的代码:

data Tree a b = Branch b (Tree a b) (Tree a b)
          | Leaf a
instance  (Show a, Show b) =>Show (Tree a b) where
show (Leaf x) = " "++show x ++"\n"
show (Branch val l r) = show val ++ "\n" ++" " ++ show l ++ " " ++ show r

这是我的测试用例和输出(这是错误的):

 Branch "<" (Branch "<" (Leaf 'a') (Leaf 'c')) (Branch "<" (Leaf 'g') (Branch     "<" (Leaf 'n') (Leaf 'y'))))
 "<"
  "<"
    'a'
    'c'
  "<"
    'g'
  "<"
    'n'
    'y'

正确的输出

 "<"
  "<"
    'a'
    'c'
  "<"
    'g'
    "<"
      'n'
      'y'

任何帮助都会很棒!

4 个答案:

答案 0 :(得分:4)

您的显示功能无法知道缩进每行的深度。在子树上添加空格是行不通的,因为它们通常会有多行。

您需要定义一个辅助函数,该函数将缩进作为参数:

indent n x = concat (replicate n " ") ++ show x ++ "\n"

f n (Leaf x) = indent n x
f n (Branch val l r) = indent n val ++ f (n+1) l ++ f (n+1) r

instance (Show a, Show b) => Show (Tree a b) where
  show tree = f 0 tree

答案 1 :(得分:2)

请考虑以下事项:

putStrLn ("First line" ++ "   " ++ "\n" ++ "Second line")

输出

First line   
Second line

因为换行符不保留缩进。您需要找到一种方法来通知show您要打印的每个项目需要多大的缩进。

答案 2 :(得分:1)

注意:这篇文章是用文字Haskell编写的。将其复制到您喜欢的编辑器中,将其保存为Tree.lhs或类似的,并将其加载到GHCi中。

让我们尝试一下其他方法。我们不是将树显示为单个字符串,而是创建字符串的行:

> data Tree a b = Branch b (Tree a b) (Tree a b) | Leaf a

> instance (Show a, Show b) => Show (Tree a b) where
>   show tree = magic (go tree)
>      where
>        go :: (Show a, Show b) => Tree a b -> [String]

不要担心magic,它会有magic :: [String] -> String类型。 让我们首先关注go。如果我们想要显示单个Leaf,我们只需关注一个值:

>        go (Leaf v)       = [show v]

现在关于分支及其缩进。我们仍然可以在Leaf案例中显示该值:

>        go (Branch v l r) = show v

但我们必须确保实际的分支在前面有正确的空白量。我们使用一个名为indent的函数(尚未定义):

>                        : indent (go l ++ go r)

现在我们已经掌握了几乎所有内容:如果indent执行其名称所暗示的内容,则会将[String]返回的go l ++ go r中的所有字符串缩进一个空格。因此,树的分支在前面总是会有一个空间作为根本身。现在缺少的只是indentmagic

>        indent :: [String] -> [String]
>        indent = map (' ':)

这很容易。你当然可以用其他东西交换(' ':)

现在magic的工作就是把所有的琴弦都粘在一起。由于您想要将整个树缩进一个空格,我们最后一次使用indent

>        magic = unlines . indent

就是这样。以下是更好概述的完整代码:

instance (Show a, Show b) => Show (Tree a b) where
  show tree = magic (go tree)
    where
      go (Leaf v)       = [show v]
      go (Branch v l r) = show v : indent (go l ++ go r)
      indent            = map (' ':)
      magic             = unlines . indent

关于这种技术的好处是我们永远不必使用显式级别或在某处陈述空格的数量。我们可以走树,创建我们的[String],让magicindent为我们完成剩下的工作。

答案 3 :(得分:0)

Your Tree type annoys me a little bit because it's a monad but can't be a Monad. Let me fix that for you by flipping the type arguments:

data Tree b a = Branch b (Tree a b) (Tree a b)
              | Leaf a

display' :: (Show a, Show b) => String -> Tree b a -> String -> String
display' prefix (Leaf a) =
  (prefix ++) . shows a . ('\n' :)
display' prefix (Branch v l r) =
  (prefix ++) . shows v . ('\n' :) . display' prefix' l . display' prefix' r
  where prefix' = ' ' : prefix

display :: (Show a, Show b) => Tree b a -> String
display t = display' ' ' t ""