Given the following filtering functions as unary predicates,
f1 :: Int -> Bool
f1 x = x > 30
f2 :: Int -> Bool
f2 x = x < 60
f3 :: Int -> Bool
f3 x = x `mod` 3 == 0
I'd like to filter a list of integers through all of them. Currently I'm doing something along the lines of:
filtered = filter f1 $ filter f2 $ filter f3 [1..90]
-- [33,36,39,42,45,48,51,54,57]
but it hardly feels like this is the most elegant solution possible; especially I don't like the multiple repetitions of filter
and the lack of composability.
Would there be a way to compose all these predicates into one, let's name it <?>
, so that a possible syntax would resemble something like the following?
filtered = filter (f1 <?> f2 <?> f3) [1..90]
-- [33,36,39,42,45,48,51,54,57]
The type signature of this hypothetical <?>
operator would then be (a -> Bool) -> (a -> Bool) -> (a -> Bool)
but I wasn't able to find any such thing on Hoogle.
What about this?
import Control.Applicative (liftA2)
-- given f1, f2, and f3
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 <$>
.