我有一棵树:
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 []]
通过树累积总和。这是否有标准功能?
答案 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
答案 2 :(得分:1)
更新:这会产生与请求不同的结果;但它显示了一个有价值的一般方法,在适用的情况下可以提供帮助,并且在这里也很有用,作为对应点。
完全可以使用base
和GHC进行这种遍历。您要查找的课程是Traversable
和mapAccum{R,L}
函数以及fst
或snd
:
让我们避免编写我们自己的实例:
{-# 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 []
]