我的树定义如下:
data Tree a = Leaf a | Node (Tree a) (Tree a) deriving (Show)
我想编写一个过滤函数,它只选择数组的每个第3个元素(第1,第4,第7,......)。例如,假设我的树如下:
Node
(Node
(Node
(Leaf 'a')
(Leaf 'b'))
(Leaf 'c'))
(Node
(Node
(Leaf 'd')
(Leaf 'e'))
(Leaf 'f'))
然后,过滤器函数应该生成一个新树:
Node (Leaf 'a') (Leaf 'd')
答案 0 :(得分:4)
这是适合你的游戏计划。
编写一个函数,将函数应用于树的每个元素。
mapTree :: (a -> b) -> Tree a -> Tree b
(加分:将Tree
设为Functor
个实例,并使用fmap
代替mapTree
)
编写一个函数,按照从左到右的顺序标记树的元素。
labelTree :: Tree a -> Tree (Integer, a)
(提示:你需要一个辅助函数,它接受一个“当前标签”并返回带标签的树和一个新标签;即:: Integer -> Tree a -> (Tree (Integer, a), Integer)
。这个函数的分支情况如下:
aux n (Branch l r) =
let (l', n') = aux n l
(r', n'') = aux n' r in
(Branch l' r', n'')
仔细阅读此代码,然后看看您是否可以提出Leaf
案例
(奖励:使用State
monad)
编写一个函数,删除不满足条件的树的元素。
filterTree :: (a -> Bool) -> Tree a -> Maybe (Tree a)
请注意,我们返回的是Maybe (Tree a)
而不仅仅是Tree a
- 这是因为如果没有符合条件的元素,我们需要返回一些内容,并且您的Tree
类型会不允许空树。事实上,返回Maybe (Tree a)
也使这个函数非常简单地递归写入。
结合使用这些函数来获取您正在寻找的功能 - 仅过滤掉可被3整除的标签的元素。
以这种方式分解它的好处在于,除了解决您的特定问题之外,您还编写了许多通用的工具来处理Tree
类型。映射和过滤器是在实现数据结构时出现的非常常见的功能。
高级: State
的{{1}} monad奖励实现是另一种称为"traversal"的常见函数类型的特定情况:
labelTree
就像一张地图,但也结合了每个元素上可能出现的“效果”。超级双加奖金,如果你可以实现它然后用它来写traverse :: (Applicative f) => (a -> f b) -> Tree a -> f (Tree b)
。