Elegant way to combine multiple filtering functions in Haskell
What about this?
import Control.Applicative (liftA2)
-- given f1 etc.
filtered = filter (f1 <&&> f2 <&&> f3) [1..90]
where
(<&&>) = liftA2 (&&)
Here, lifting &&
to Applicative
gives what you marked as <?>
, i.e. an operator to "and" together the results of two unary predicates.
I initially used the name .&&.
for the lifted operator, but amalloy suggested that <&&>
would be a better name by analogy with the other Functor
/Applicative
lifted operators like <$>
.
> filter (and . sequence [f1, f2, f3]) [1..100]
[33,36,39,42,45,48,51,54,57]
Essentially the above works because sequence
(on the (->) a
monad as used above) takes a list-of-functions and returns a function-returning-a-list. E.g.
sequence [f, g, h] = \x -> [f x, g x, h x]
Post-composing with and :: [Bool] -> Bool
gives you a single boolean result, so you can use that in filter
.
Also, there is no shame in being point-ful:
> filter (\x -> f1 x && f2 x && f3 x) [1..100]
is only marginally longer, and arguably simpler to read.