我已经定义了一个树数据类型如下:
data Tree a = T (Tree a, Tree a) | Leaf a deriving (Show, Eq, Ord)
我希望根据特定条件过滤此树。我试着写的功能是:
filterT :: (a -> Bool) -> Tree a -> Tree a
filterT c (T(Leaf x,T(t1,t2))) = if c x
then (T(Leaf x, T(filterT c t1, filterT c t2)))
else T(filterT c t1,filterT c t2)
此函数无法正常工作,因为在两个叶值(最后)都不满足条件的情况下,函数无法返回。如果你能提供帮助,我将不胜感激。
答案 0 :(得分:3)
部分问题在于您根本无法表示空树。
-- Get rid of unnecessary tuple
data Tree a = Empty
| Leaf a
| T (Tree a) (Tree a) deriving (Show, Eq, Ord)
-- A filtered empty tree is still empty
filterT p Empty = Empty
-- A leaf either stays the same or becomes empty
filterT p (Leaf x) | p x = Leaf x
| otherwise = Empty
-- Any other tree is just the result of filtering each child
filterT p (T left right) = T (filterT p left) (filterT p right)
这不是一个很好的修复;它仍然为您提供了多种表示基本相同树的方法,因为Empty
和T Empty Empty
没有显着差异。您可以编写另一个函数来“修剪”这样的树。
prune :: Tree a -> Tree a
prune (T Empty Empty) = Empty
prune x = x
可以合并到filterT
函数中,如下所示:
filterT _ Empty = Empty
filterT p (Leaf x) | p x = Leaf x
| otherwise = Empty
filterT p (T left right) = let prune (T Empty Empty) = Empty
prune x = x
in prune $ T (filterT p left) (filterT p right)
您也可以将prune
扩展为将单叶树合约为一片叶子(Tree (Leaf 3) Empty
和Leaf 3
应该被视为同一棵树?),如
filterT' _ Empty = Empty
filterT' p (Leaf x) | p x = Leaf x
| otherwise = Empty
filterT' p (T left right) = let prune (T Empty Empty) = Empty
prune (T (Leaf x) Empty)) = Leaf x
prune (T Empty (Leaf x)) = Leaf x
prune x = x
in prune $ T (filterT p left) (filterT p right)
最后,您是否使用prune
将取决于过滤后的树是否应该保留原始结构;也许你想区分叶子和曾经有两个孩子的节点,例如。
答案 1 :(得分:2)
整个树中的项目可能不满足条件。然后你将有一个空树。因此,您必须将树的定义扩展为:
data Tree a = Empty | Leaf a | Node (Tree a) (Tree a)
即,包括Empty
树的大小写或将filterT
的签名更改为:
filterT :: (a -> Bool) -> Tree a -> Maybe (Tree a)
这样就可以返回Nothing
。
采用第二种方法(1),可能的方法是派生Foldable
实例并根据右侧折叠定义过滤函数:
data Tree a = Leaf a | Node (Tree a) (Tree a)
deriving Show
instance Foldable Tree where
foldr f z (Leaf x) = f x z
foldr f z (Node l r) = foldr f (foldr f z r) l
filterT :: (a -> Bool) -> Tree a -> Maybe (Tree a)
filterT f = foldr go Nothing
where
go x z = if not (f x) then z else Just $ case z of
Nothing -> Leaf x
Just tr -> Node (Leaf x) tr
<子>
1.因为它使数据类型更简单,并避免冗余的Node Empty Empty
值。
子>