使用多个参数映射树

时间:2014-02-14 21:34:07

标签: haskell tree

我遇到了地图函数和递归的问题。

我有一个像这样的Tree数据结构:

data Tree a = T a [Tree a] deriving (Eq,Ord,Show)

我已经有了一个工作函数来计算“通过”工作的树。

count :: Tree a -> Int
count (T _ xs) = 1 + sum(map count xs)

不,我想要一个函数来用谓词

来证明树的每个元素
filterKnoten :: (a -> Bool) -> Tree a -> [a]
filterKnoten p (T x []) = (if p(x) then [x] else []) 
filterKnoten p (T x xs) 
                    | p(x) == True = x:(map multP xs)
                    | p(x) == False = map multP xs
                    where multP = filterKnoten p

一些样本日期将是

ex1 = T True [T False [T True[]] , T True []]
当我用例如

调用方法时,

filterKnoten (==True) ex1

结果我希望列出包含所有符合我的谓词的元素,但是当我想加载模块时,编译给了我这个

Couldn't match type `a' with `[a]'
  `a' is a rigid type variable bound by
      the type signature for filterKnoten :: (a -> Bool) -> Tree a -> [a]
      at WS11.hs:138:17
Expected type: Tree a -> a
  Actual type: Tree a -> [a]
In the first argument of `map', namely `multP'
In the expression: map multP xs
In an equation for `filterKnoten':
    filterKnoten p (T x xs)
      | p (x) == True = x : (map multP xs)
      | p (x) == False = map multP xs
      where
          multP = filterKnoten p
Failed, modules loaded: none.

所以我的问题是,为什么地图适用于count而不是filterKnoten?

提前致谢

2 个答案:

答案 0 :(得分:5)

我认为使用递归编写函数是一项有用的练习,但从实际角度来看,您可以使用GHC扩展来推导所有这些函数:

{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}

import Data.Foldable    
import Data.Traversable 

data Tree a = T a [Tree a] deriving (Eq,Ord,Show, Functor, Traversable, Foldable)

filterTree :: (a -> Bool) -> Tree a -> [a]
filterTree f = filter f . toList  -- toList is defined in Foldable

此示例您不需要Traversable,它只是您可以推导出的其他有用内容之一。

答案 1 :(得分:2)

您的主要问题是您正在映射T a -> [a]类型的函数,该函数会返回[[a]]而不是您想要的[a]。可以通过将map更改为concatMap

Data.List来解决此问题
import Data.List
...
filterKnoten :: (a -> Bool) -> Tree a -> [a]
filterKnoten p (T x []) = if p x then [x] else []
filterKnoten p (T x xs) 
                    | p x       = x:(concatMap multP xs)
                    | otherwise = concatMap multP xs
                    where multP = filterKnoten p

请注意,我还摆脱了无用的==True==Falsex == Truex完全相同,当我们谈论案例时,两次计算相同的事情毫无意义。特别是因为它可能非常昂贵。 otherwise只是前奏提供的True的同义词。我也摆脱了一些不必要的麻烦。

最后,您可以转储整个第一个案例,因为mapconcatMap处理空列表。