Haskell过滤器的第一个元素

时间:2015-03-06 00:53:31

标签: haskell

我想删除没有特定属性的第一个元素。 例如,如果我的属性定义为...

greaterOne :: Num a=>Ord a=>a->Bool
greaterOne x = x > 1

然后函数filterFirst应该给我这个......

filterFirst greaterOne [5,-6,-7,9,10]
>> [5,-7,9,10]  //removes first element that is not greater than one

这是我的尝试......

filterFirst :: (a->Bool)->[a]->[a]
filterFirst p [] = []
filterFirst p (x:y:xs)
    |p x = filterFirst p xs
    |otherwise = y:xs

有人能帮助我吗?

2 个答案:

答案 0 :(得分:6)

了解您的尝试:[]被发送到[](这是正确的)。如果列表中包含至少两个元素(x:y:xs),则您的函数会测试x会抛出xy 并继续过滤test 传递(绝对不是你想要的),并抛出x并在测试失败时停止(这是正确的)。一个包含单个元素错误的列表,以及具有奇数个元素的许多其他列表(这都是错误的,并且是正确答案的线索)。

让我们一步一步地完成正确的实施。正如您所写,我们希望filterFirstaa列表中使用谓词,并返回另一个a列表:

filterFirst :: (a -> Bool) -> [a] -> [a]

谓词类型a -> Bool无法细分,但[a]可以:可以有空列表[]和非空列表x:xs,并且应该有每个案例:

filterFirst p []     = ...
filterFirst p (x:xs) = ...

在“基本情况”[]中,没有任何内容可供过滤,因此我们希望这是[],这就是您所写的内容。由于此处未使用p,因此您可以使用p替换_

filterFirst _ [] = []

但你没必要。

我们想要对x:xs做什么取决于p x的值。如果p x成立,我们需要一个以x开头的列表。此列表的尾部应为xs,但删除了第一个失败元素。如果p x失败,我们要抛弃x(第一个失败元素)并保留xs(第一个失败元素之后的列表)。所以:

filterFirst p (x:xs)
    | p x       = x:filterFirst p xs
    | otherwise = xs

这涵盖了所有可能性,所以我们已经完成了!

根据dfeuer的评论

编辑

答案 1 :(得分:4)

您可以滥用deleteBy

> deleteBy (>) 1 [5, -6, -7, 9, 10]
[5,-7,9,10]

......更一般地说:

filterFirst p = deleteBy (const p) undefined