如何组合过滤条件

时间:2009-05-08 21:20:39

标签: haskell filter

过滤器类函数采用条件(a - > Bool)并在过滤时应用它。

当您有多个条件时,使用过滤器的最佳方法是什么?

使用了应用功能 liftA2而不是liftM2,因为我出于某种原因不明白liftM2如何在纯代码中工作。

4 个答案:

答案 0 :(得分:30)

liftM2组合器可以在Reader monad中以“更实用”的方式使用:

import Control.Monad
import Control.Monad.Reader

-- ....

filter (liftM2 (&&) odd (> 100)) [1..200]

请注意,进口很重要; Control.Monad.Reader提供Monad(e - >)实例,使其全部工作。

这个工作的原因是读者monad只是(e - >)对于某些环境e。因此,布尔谓词是0-ary monadic函数,在与其参数对应的环境中返回bool。然后我们可以使用liftM2将环境分布在两个这样的谓词上。

或者,简单来说,当类型解决时,liftM2会有点像这样:

liftM2 f g h a = f (g a) (h a)

如果您希望能够轻松地链接这些组合器,并且/或者不想弄乱liftM2,您也可以定义新的组合器:

(.&&.) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
(.&&.) f g a = (f a) && (g a)
-- or, in points-free style:
(.&&.) = liftM2 (&&)    

filter (odd .&&. (> 5) .&&. (< 20)) [1..100]

答案 1 :(得分:15)

好吧,你可以在Haskell中组合你想要的函数(只要类型是正确的)并使用lambdas你甚至不必命名你的谓词函数,即

filter (\x -> odd x && x > 100) [1..200]

答案 2 :(得分:11)

假设您的条件存储在名为conditions的列表中。此列表的类型为[a -> Bool]

要将所有条件应用于值x,您可以使用map

map ($ x) conditions

这会将每个条件应用于x并返回Bool列表。要将此列表减少为单个布尔值,如果所有元素都为True,则为True,否则为False,则可以使用and函数:

and $ map ($ x) conditions

现在你有一个结合所有条件的功能。我们给它一个名字:

combined_condition x = and $ map ($ x) conditions

此函数的类型为a -> Bool,因此我们可以在调用filter时使用它:

filter combined_condition [1..10]

答案 3 :(得分:3)

如果你有一个a -> Bool类型的过滤函数列表,并希望将它们组合成一个相同类型的简洁过滤函数,我们可以编写函数来做。您使用的以下两个函数中的哪一个取决于您需要的过滤器行为。

anyfilt :: [(a -> Bool)] -> (a -> Bool)
anyfilt fns = \el -> any (\fn -> fn el) fns

allfilt :: [(a -> Bool)] -> (a -> Bool)
allfilt fns = \el -> all (\fn -> fn el) fns

anyfilt将返回如果任何过滤器函数返回true,则返回true ,如果所有过滤器函数返回false,则返回false。 如果所有过滤器函数都返回true,则allfilt将返回true;如果任何过滤器函数返回false ,则{strong> false将返回false。 请注意,您不能η-减少任何一个函数,因为RHS上fns的引用是在匿名函数内。

像这样使用:

filterLines :: [String] -> [String]
filterLines = let
  isComment = isPrefixOf "# "
  isBlank = (==) ""
  badLine = anyfilt([isComment, isBlank])
  in filter (not . badLine)

main = mapM_ putStrLn $ filterLines ["# comment", "", "true line"]
--> "true line"