我遇到了地图函数和递归的问题。
我有一个像这样的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?
提前致谢
答案 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
和==False
。 x == True
与x
完全相同,当我们谈论案例时,两次计算相同的事情毫无意义。特别是因为它可能非常昂贵。 otherwise
只是前奏提供的True
的同义词。我也摆脱了一些不必要的麻烦。
最后,您可以转储整个第一个案例,因为map
和concatMap
处理空列表。