4

学习Haskell,我正在尝试编写一个takeIf给定条件的函数,并且列表返回满足条件的所有列表元素。

所需输出的示例:

takeIf (>0) [] --> []
takeIf (>0) [-1, 0, 1, 2] --> [1,2]

我试过这个定义:

takeIf cond [] = []
takeIf cond (x:xs) = if (cond x) 
                    then x:(takeIf cond xs)
                    else []:(takeIf cond xs)

但它不起作用。

我的第一个问题是:我有

:t takeIf --> ([a] -> Bool) -> [[a]] -> [[a]]

为什么?为什么不:

:t takeIf --> (a -> Bool) -> [a] -> [a]

我怎样才能让这个代码工作?

这是我得到的错误:

在此处输入图像描述

如果有帮助,我正在使用ghci

4

3 回答 3

10
[]:(takeIf cond xs)

在这里,您尝试将 [] 作为新的第一个元素添加到takeIf cond xs. 由于[]是一个列表,GHC 从中推断出结果takeIf cond xs必须是一个列表的列表。由于 takeIf 的结果与其参数具有相同的类型,这意味着xs也必须是列表的列表。并且由于x是 的一个元素xsx因此必须是一个列表。

似乎您[]:的意思是“在列表中不添加任何内容”,但[]不是什么都没有,它是空列表。[] : [],不给你[],它给你[[]]。同样[] : [1,2,3]会给你[[], 1, 2, 3]- 除了那不是很好的类型,所以它真正给你的是一个类型错误。

如果您不想在列表中添加任何内容,请不要在列表中添加任何内容,即只需使用someList而不是[] : someList.

于 2012-06-02T17:06:56.207 回答
3

因为 sepp2k 比我快 - 我只想补充一点,您可能想看看filter它的源代码,这正是您尝试重新实现的功能。
这是实际来源

filter :: (a -> Bool) -> [a] -> [a]
filter _pred []    = []
filter pred (x:xs)
  | pred x         = x : filter pred xs
  | otherwise      = filter pred xs
于 2012-06-02T17:14:51.197 回答
0

另一种选择是折叠,例如

filter' f = foldr go [] where 
   go x xs = if f x then x:xs else xs
于 2012-06-03T10:24:15.090 回答