我有一个树的数据定义:
data Tree = Leaf Int | Node Tree Int Tree
我必须创建一个函数nSatisfy
来检查树的多少项检查一些谓词。
这就是我所做的:
nSatisfy :: (Int->Bool) -> Tree -> Int
nSatisfy _ Leaf = 0
nSatisfy y (Node left x right)
|y x = 1 + nSatisfy y (Node left x right)
| otherwise = nSatisfy y (Node left x right)
这是解决此问题的正确方法吗?
答案 0 :(得分:3)
在nSatisfy
函数中,您应该在两个子树中添加满足条件的节点数和两个递归调用。最后两行应该是这样的:
|x y=1+(nSatisfy y left)+(nSatisfy y right)
|otherwise=(nSatisfy y left)+(nSatisfy y right)
这样,它将在同一节点上再次调用自身,但仅在子树上调用。
此外,如果一个叶子包含一个整数,如数据声明中暗示的那样,你应该让它评估一个叶子的条件,如果为真,则返回1,而不是总是返回0。
答案 1 :(得分:2)
除了主要答案之外,我还想提供一种略有不同的方法,如何概括问题并使用现有的库来解决问题。
您正在寻找的操作对于许多数据结构是通用的 - 遍历所有元素并对它们执行某些操作。 Haskell定义了Foldable type-class,它可以像你这样的结构实现。
首先让我们导入一些我们需要的模块:
import Data.Foldable
import Data.Monoid
为了使用Foldable
,我们需要稍微概括一下结构,特别是对其内容进行参数化:
data Tree a = Leaf a | Node (Tree a) a (Tree a)
在许多情况下,这是一个好主意,因为它将结构与其内容分开,并允许它轻松重复使用。
现在让我们定义它的Foldable
实例。对于树状结构,使用foldMap
更容易定义它,它将每个元素映射到monoid,然后组合所有值:
instance Foldable Tree where
foldMap f (Leaf x) = f x
foldMap f (Node lt x rt) = foldMap f lt <> f x <> foldMap f rt
这立即为我们提供了Data.Foldable
模块中的整个函数库,例如搜索元素,不同类型的折叠等。虽然没有定义计算满足某个谓词的值的数量的函数在那里,我们可以轻松地为任何Foldable
定义它。我们的想法是使用Sum
:
nSatisfy :: (Foldable f) => (a -> Bool) -> f a -> Int
nSatisfy p = getSum . foldMap (\x -> Sum $ if p x then 1 else 0)
这个函数背后的想法很简单:如果它满足谓词,则将每个值映射到1
,否则映射到0
。然后使用Sum
monoid进行折叠只会添加所有值。