Haskell - 树中的总和值

时间:2015-03-06 07:47:45

标签: haskell functional-programming

我的树看起来像这样,一棵树在每个节点都可以有或没有整数:

data Tree = Empty | Node (Maybe Integer) Tree Tree deriving Show

我想总结树中的所有值,不包括Nothing值,如果tree不为空但只有Nothing值,只返回Nothing,或者空树为0.这些情况我理解如何。

我想深入思考第一次遍历是最好的,或者只是一般的基本遍历,但是如何优雅地实现它。

treeValues :: Tree - >也许是整数

4 个答案:

答案 0 :(得分:6)

您可以将您的树设为Foldable个实例,并免费获得许多功能,包括sum

  

sum ::(可折叠t,Num a)=> t a - >来源

     

sum函数计算结构数的总和。

但您需要将Tree设为参数类型:

data Tree a = Empty | Node (Maybe a) Tree Tree

此外,使用GHC 7.10,几乎所有Prelude函数都将使用FoldableTraversable类型类而不是列表,然后您可以自由地为树使用它们,如果您实现这些类型类。

答案 1 :(得分:5)

您已经知道如何对列表求和,因此您可以先将树转换为列表:

> toList :: Tree -> [Integer]
> toList Empty        = []
> toList (Node a l r) = maybeToList a ++ toList l ++ toList r
>   where maybeToList (Just x) = [x]
>         maybeToList Nothing  = []

现在,您希望在空树(Empty)和仅包含Nothing的树之间有所不同。由于toList过滤了所有Nothing值,因此归结为

> sumTree :: Tree -> Maybe Integer
> sumTree Empty = Just 0
> sumTree tree  = case toList tree of
>                  [] -> Nothing      -- all values in the tree are Nothing
>                  xs -> Just $ sum xs       -- some were Just x

但等等,还有更多!

sumTree还不是很好。如果我们想要计算Tree的乘积怎么办?嗯。好吧,我们可以拿一棵树,把它变成一个列表,并使用......折叠功能!

> type I = Integer -- otherwise the lines get ridiculously long
>
> foldrTree' :: (I -> I -> I) -> I -> Tree -> Maybe I
> foldrTree' _ init Empty = init
> foldrTree' f init tree  = case toList tree of
>                            [] -> Nothing
>                            xs -> Just $ foldr f init xs
> --                                      ^^^^^

现在我们可以使用任何(Integer -> Integer -> Integer)并生成单个值,只要我们的操作是关联的:

> productTree :: Tree -> Maybe Integer
> productTree = foldrTree' (*) 1
>
> sumTree' :: Tree -> Maybe Integer
> sumTree' = foldrTree' (+) 0

答案 2 :(得分:4)

这里有一个提示:

data Tree a = Empty | Node a (Tree a) (Tree a)

reduce :: (a -> r -> r -> r) -> r -> Tree a -> r
reduce f z = go
    where
        go Empty        = z
        go (Node x l r) = f x (go l) (go r)

答案 3 :(得分:1)

关于上述解决方案和评论以及lyahBrent Yorgeys advice,我汇编了以下提案(在ghci中尝试使用):

:set -XDeriveFoldable -XDeriveFunctor
:m + Data.Foldable Data.Monoid
data Tree a = Empty | Node (Maybe a) (Tree a) (Tree a) deriving (Show, Functor, Foldable)
let tree :: Tree Integer ; tree = Node Nothing (Node (Just 42) Empty Empty) (Node Nothing Empty Empty)
foldMap Sum tree

虽然在两种情况下只返回0,但只给出了Nothing个值,而树是Empty但我希望它稍后会为像我这样的学习者提示。