考虑以下数据类型
data Tree a b = Branch b (Tree a b) (Tree a b) | Leaf a
我试图定义一个Show的实例(不导入任何模块或使用派生),它会像这样显示树
Main*> let a = Branch "x" (Branch "y" (Leaf 4) (Leaf 7)) (Leaf 9)
Main*> a
"x"
"y"
4
7
9
到目前为止,这是我提出的
findDepth (Leaf a) = 0
findDepth (Branch a (b) (c)) = 1 + (max (findDepth b) (findDepth c))
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
show (Branch a (b) (c)) =
show a ++ "\n" ++ s2 ++ show b ++ "\n" ++ s2 ++ show c ++ "\n" ++ s1
where
d = findDepth (Branch a (b) (c))
s1 = addSpace (d-1)
s2 = addSpace d
addSpace n = replicate n '\t'
不幸的是,这会使深度最低的节点和最低深度节点的节点缩进。我知道findDepth函数实际上应该为leaf赋予最大值并分支最低值,但是无法找到为两个参数递归写入函数的方法。有什么建议吗?
答案 0 :(得分:4)
实际上,不需要额外的findDepth
功能 - 每次展示孩子时,您都可以轻松遍历树并增加深度:
import Text.Printf
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 = showAtLevel 0
where
showAtLevel l (Leaf x) = addSpace l ++ show x
showAtLevel l (Branch x (lt) (rt)) = printf "%s%s\n%s\n%s" (addSpace l) (show x) (showAtLevel (l + 1) lt) (showAtLevel (l + 1) rt)
addSpace = flip replicate '\t'
测试用例:
*Main> let a = Branch "x" (Branch "y" (Leaf 4) (Leaf 7)) (Leaf 9)
*Main> a
"x"
"y"
4
7
9
*Main> Branch "x" (Branch "y" (Leaf 4) (Branch "z" (Leaf 42) (Leaf 314))) (Leaf 9)
"x"
"y"
4
"z"
42
314
9
答案 1 :(得分:2)
这里有一个没有完整解决方案的提示:编写一个单一的函数showWithDepth :: Int -> Tree -> String
来传递"累积的深度"至今。然后你可以写show = showWithDepth 0
。
请注意,一般情况下,不应该这样写show
个实例,因为它的"半标准" show实例应该基本上像派生实例一样工作,并生成类似于有效Haskell代码的东西。 (此外,在Read
个实例存在的情况下,我们需要read . show === id
。