在Haskell上,有一个标准函数执行" scan"在树上?

时间:2015-01-04 07:26:33

标签: haskell tree foldable

我有一棵树:

a :: Tree Double
a = 
    Node 1 
       [Node 20 
           [Node 300 
               [Node 400 [], 
               Node 500 []], 
           Node 310 []], 
       Node 30 [], 
       Node 40 []]

我想将它应用于类似于列表的scan操作 - 除了它不应该返回列表,它应该返回一个带有行进路径的树。例如:

scan (+) 0 a

应减少到:

Node 1 
    [Node 21 
        [Node 321 
            [Node 721 [], 
            Node 821 []], 
        Node 331 []], 
    Node 31 [], 
    Node 41 []]

通过树累积总和。这是否有标准功能?

3 个答案:

答案 0 :(得分:3)

没有标准的库函数可以做到这一点。对于列表:Haskell几乎可以在Data.List中考虑任何函数,但Data.Tree实际上非常稀疏。

幸运的是,你想要的功能非常简单。

scan f ~(Node r l) = Node r $ map (fmap (f r) . scan f) l

- 编辑 -

上述功能有一个问题:在OP给出的例子中,它计算了" 721" as" 1 +(20 +(400 + 300))",这会阻止" 1 + 20"在其他分支中重复使用的计算。

以下功能没有这个问题,但是我保留原来的功能,因为根据作为第一个参数传递的功能,它仍然有用。

scan f ~(Node r l) = Node r $ map (scan' r) l where
  scan' a ~(Node n b) = let a' = f a n in Node a' $ map (scan' r) b 

答案 1 :(得分:2)

如果要传递累加器,则定义为

scan f a (Node x ns) = Node a' $ map (scan f a') ns where a' = f a x

此版本效率更高,比较thisthis

答案 2 :(得分:1)

更新:这会产生与请求不同的结果;但它显示了一个有价值的一般方法,在适用的情况下可以提供帮助,并且在这里也很有用,作为对应点。

完全可以使用base和GHC进行这种遍历。您要查找的课程是TraversablemapAccum{R,L}函数以及fstsnd

让我们避免编写我们自己的实例:

{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}

现在我们可以得出必要的部分:

import Data.Traversable
import Data.Foldable

data Tree a = Node a [Tree a]
            deriving (Functor, Traversable, Foldable, Show)

然后使用非常简单。如果您不想要最终的累加器,那么只需使用snd

main :: IO ()
main = print $ mapAccumL (\acc e -> (acc+e,acc+e)) 0 demo

demo :: Tree Int
demo =
   Node 1 [Node 20.
            [Node 300 [Node 400 []
                      , Node 500 []]
            , Node 310 []
            ]
          , Node 30 [], Node 40 []
          ]