在Haskell中使用树

时间:2014-01-19 17:50:20

标签: haskell

我有一个树的数据定义:

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)

这是解决此问题的正确方法吗?

2 个答案:

答案 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进行折叠只会添加所有值。