I need binary combinators of the type
(a -> Bool) -> (a -> Bool) -> a -> Bool
or maybe
[a -> Bool] -> a -> Bool
(though this would just be the foldr1 of the first, and I usually only need to combine two boolean functions.)
Are these built-in?
If not, the implementation is simple:
both f g x = f x && g x
either f g x = f x || g x
or perhaps
allF fs x = foldr (\ f b -> b && f x) True fs
anyF fs x = foldr (\ f b -> b || f x) False fs
Hoogle turns up nothing, but sometimes its search doesn't generalise properly. Any idea if these are built-in? Can they be built from pieces of an existing library?
If these aren't built-in, you might suggest new names, because these names are pretty bad. In fact that's the main reason I hope that they are built-in.
Control.Monad defines an instance Monad ((->) r), so
ghci> :m Control.Monad
ghci> :t liftM2 (&&)
liftM2 (&&) :: (Monad m) => m Bool -> m Bool -> m Bool
ghci> liftM2 (&&) (5 <) (< 10) 8
True
You could do the same with Control.Applicative.liftA2.
Not to seriously suggest it, but...
ghci> :t (. flip ($)) . flip all
(. flip ($)) . flip all :: [a -> Bool] -> a -> Bool
ghci> :t (. flip ($)) . flip any
(. flip ($)) . flip any :: [a -> Bool] -> a -> Bool
It's not a builtin, but the alternative I prefer is to use type classes to generalize
the Boolean operations to predicates of any arity:
module Pred2 where
class Predicate a where
complement :: a -> a
disjoin :: a -> a -> a
conjoin :: a -> a -> a
instance Predicate Bool where
complement = not
disjoin = (||)
conjoin = (&&)
instance (Predicate b) => Predicate (a -> b) where
complement = (complement .)
disjoin f g x = f x `disjoin` g x
conjoin f g x = f x `conjoin` g x
-- examples:
ge :: Ord a => a -> a -> Bool
ge = complement (<)
pos = (>0)
nonzero = pos `disjoin` (pos . negate)
zero = complement pos `conjoin` complement (pos . negate)
I love Haskell!
I don't know builtins, but I like the names you propose.
getCoolNumbers = filter $ either even (< 42)
Alternately, one could think of an operator symbol in addition to typeclasses for alternatives.
getCoolNumbers = filter $ even <|> (< 42)
Related
How can I get a maximum element of an effectful container where computing attribute to compare against also triggers an effect?
There has to be more readable way of doing things like:
latest dir = Turtle.fold (z (ls dir)) Fold.maximum
z :: MonadIO m => m Turtle.FilePath -> m (UTCTime, Turtle.FilePath)
z mx = do
x <- mx
d <- datefile x
return (d, x)
I used overloaded version rather than non-overloaded maximumBy but the latter seems better suite for ad-hoc attribute selection.
How can I be more methodic in solving similar problems?
So I know nothing about Turtle; no idea whether this fits well with the rest of the Turtle ecosystem. But since you convinced me in the comments that maximumByM is worth writing by hand, here's how I would do it:
maximumOnM :: (Monad m, Ord b) => (a -> m b) -> [a] -> m a
maximumOnM cmp [x] = return x -- skip the effects if there's no need for comparison
maximumOnM cmp (x:xs) = cmp x >>= \b -> go x b xs where
go x b [] = return x
go x b (x':xs) = do
b' <- cmp x'
if b < b' then go x' b' xs else go x b xs
I generally prefer the *On versions of things -- which take a function that maps to an Orderable element -- to the *By versions -- which take a function that does the comparison directly. A maximumByM would be similar but have a type like Monad m => (a -> a -> m Ordering) -> [a] -> m a, but this would likely force you to redo effects for each a, and I'm guessing it's not what you want. I find *On more often matches with the thing I want to do and the performance characteristics I want.
Since you're already familiar with Fold, you might want to get to know FoldM, which is similar.
data FoldM m a b =
-- FoldM step initial extract
forall x . FoldM (x -> a -> m x) (m x) (x -> m b)
You can write:
maximumOnM ::
(Ord b, Monad m)
=> (a -> m b) -> FoldM m a (Maybe a)
maximumOnM f = FoldM combine (pure Nothing) (fmap snd)
where
combine Nothing a = do
f_a <- f a
pure (Just (f_a, a))
combine o#(Just (f_old, old)) new = do
f_new <- f new
if f_new > f_old
then pure $ Just (f_new, new)
else pure o
Now you can use Foldl.foldM to run the fold on a list (or other Foldable container). Like Fold, FoldM has an Applicative instance, so you can combine multiple effectful folds into one that interleaves the effects of each of them and combines their results.
It's possible to run effects on foldables using reducers package.
I'm not sure if it's correct, but it leverages existing combinators and instances (except for Bounded (Maybe a)).
import Data.Semigroup.Applicative (Ap(..))
import Data.Semigroup.Reducer (foldReduce)
import Data.Semigroup (Max(..))
import System.IO (withFile, hFileSize, IOMode(..))
-- | maxLength
--
-- >>> getMax $ maxLength ["abc","a","hello",""]
-- 5
maxLength :: [String] -> (Max Int)
maxLength = foldReduce . map (length)
-- | maxLengthIO
--
-- Note, this runs IO...
--
-- >>> (getAp $ maxLengthIO ["package.yaml", "src/Lib.hs"]) >>= return . getMax
-- Just 1212
--
-- >>> (getAp $ maxLengthIO []) >>= return . getMax
-- Nothing
maxLengthIO :: [String] -> Ap IO (Max (Maybe Integer))
maxLengthIO xs = foldReduce (map (fmap Just . f) xs) where
f :: String -> IO Integer
f s = withFile s ReadMode hFileSize
instance Ord a => Bounded (Maybe a) where
maxBound = Nothing
minBound = Nothing
I am just working through some simple exercises in haskell and was wondering if there was a point-free way of converting an if-then-else statement into a Maybe type: Nothing being returned if the condition is false, and Just the input if the condition is true.
In short, given some:
maybeIf :: (a -> Bool) -> a -> Maybe a
maybeIf cond a = if cond a then Just a else Nothing
Is there an implementation that is point-free with respect to a? I've also been looking at a more concrete version, a -> Maybe a, and feel like there may be an answer somewhere in Control.Arrow. However, since Maybe is a data type and if-else statements control data flow, I'm unsure if there is a clean way of doing it.
The main thing getting in the way of making that pointfree is the if/then/else. You can define an if' combinator, or you can use this generalized version that I define and use often:
ensure p x = x <$ guard (p x)
Standard tools give successive point-free versions as
ensure p = ap (<$) (guard . p)
ensure = ap (<$) . (guard .)
though I really don't think either are better than the pointful version.
You can import find from Data.Foldable and then it's quite simply:
import Data.Foldable(find)
maybeIf cond = find cond . Just
The function find is not complicated so you could quite easily define it yourself less generically, in terms of Maybe, but it isn't actually so different from your own implementation of maybeIf so you might not gain much, depending on why you wanted to do it.
If we choose a Church-encoding for Booleans…
truth :: Bool -> a -> a -> a
truth True t f = t
truth False t f = f
Then we can write a point-free maybeIf in Applicative-style.
maybeIf :: (a -> Bool) -> a -> Maybe a
maybeIf = liftA3 truth <*> pure Just <*> pure (pure Nothing)
Some intuitions…
f <$> m₁ <*> … <*> mₙ = \x -> f (m₁ x) … (mₙ x)
liftAₙ f <$> m₁ <*> … <*> mₙ = \x -> f <$> m₁ x <*> … <*> mₙ x
Here is a rendering in PNG format of the above "intuitions", in case your installed fonts do not support the needed unicode characters.
So therefore:
liftA3 truth <*> pure Just <*> pure (pure Nothing)
= liftA3 truth <$> id <*> pure Just <*> pure (pure Nothing)
= \p -> truth <$> id p <*> (pure Just) p <*> (pure (pure Nothing)) p
= \p -> truth <$> p <*> Just <*> pure Nothing
= \p -> \a -> truth (p a) (Just a) ((pure Nothing) a)
= \p -> \a -> truth (p a) (Just a) Nothing
Following dfeuer's lead (and using Daniel Wagner's new name for this function),
import Data.Bool (bool)
-- F T
-- bool :: a -> a -> Bool -> a
ensure :: (a -> Bool) -> a -> Maybe a
ensure p x = bool (const Nothing) Just (p x) x
ensure p = join (bool (const Nothing) Just . p)
= bool (const Nothing) Just =<< p
ensure = (bool (const Nothing) Just =<<)
join is a monadic function, join :: Monad m => m (m a) -> m a, but for functions it is simply
join k x = k x x
(k =<< f) x = k (f x) x
join is accepted as a replacement for W combinator in point-free code.
You only wanted it point-free with respect to the value argument, but it's easy to transform the equation with join further (readability of the result is another issue altogether), as
= join ((bool (const Nothing) Just .) p)
= (join . (bool (const Nothing) Just .)) p
Indeed,
#> (join . (bool (const Nothing) Just .)) even 3
Nothing
#> (bool (const Nothing) Just =<<) even 4
Just 4
But I'd much rather see \p x -> listToMaybe [x | p x] in an actual code.
Or just \p x -> [x | p x], with Monad Comprehensions. Which is the same as Daniel Wagner's x <$ guard (p x), only with different syntax.
This function is defined in Control.Monad.Plus and is called partial
I am trying to compose a function of type (Floating a) => a -> a -> a with a function of type (Floating a) => a -> a to obtain a function of type (Floating a) => a -> a -> a. I have the following code:
test1 :: (Floating a) => a -> a -> a
test1 x y = x
test2 :: (Floating a) => a -> a
test2 x = x
testBoth :: (Floating a) => a -> a -> a
testBoth = test2 . test1
--testBoth x y = test2 (test1 x y)
However, when I compile it in GHCI, I get the following error:
/path/test.hs:8:11:
Could not deduce (Floating (a -> a)) from the context (Floating a)
arising from a use of `test2'
at /path/test.hs:8:11-15
Possible fix:
add (Floating (a -> a)) to the context of
the type signature for `testBoth'
or add an instance declaration for (Floating (a -> a))
In the first argument of `(.)', namely `test2'
In the expression: test2 . test1
In the definition of `testBoth': testBoth = test2 . test1
Failed, modules loaded: none.
Note that the commented-out version of testBoth compiles. The strange thing is that if I remove the (Floating a) constraints from all type signatures or if I change test1 to just take x instead of x and y, testBoth compiles.
I've searched StackOverflow, Haskell wikis, Google, etc. and not found anything about a restriction on function composition relevant to this particular situation. Does anyone know why this is happening?
\x y -> test2 (test1 x y)
== \x y -> test2 ((test1 x) y)
== \x y -> (test2 . (test1 x)) y
== \x -> test2 . (test1 x)
== \x -> (test2 .) (test1 x)
== \x -> ((test2 .) . test1) x
== (test2 .) . test1
These two things are not like each other.
test2 . test1
== \x -> (test2 . test1) x
== \x -> test2 (test1 x)
== \x y -> (test2 (test1 x)) y
== \x y -> test2 (test1 x) y
You're problem doesn't have anything to do with Floating, though the typeclass does make your error harder to understand. Take the below code as an example:
test1 :: Int -> Char -> Int
test1 = undefined
test2 :: Int -> Int
test2 x = undefined
testBoth = test2 . test1
What is the type of testBoth? Well, we take the type of (.) :: (b -> c) -> (a -> b) -> a -> c and turn the crank to get:
b ~ Int (the argument of test2 unified with the first argument of (.))
c ~ Int (the result of test2 unified with the result of the first argument of (.))
a ~ Int (test1 argument 1 unified with argument 2 of (.))
b ~ Char -> Int (result of test1 unified with argument 2 of (.))
but wait! that type variable, 'b' (#4, Char -> Int), has to unify with the argument type of test2 (#1, Int). Oh No!
How should you do this? A correct solution is:
testBoth x = test2 . test1 x
There are other ways, but I consider this the most readable.
Edit: So what was the error trying to tell you? It was saying that unifying Floating a => a -> a with Floating b => b requires an instance Floating (a -> a) ... while that's true, you really didn't want GHC to try and treat a function as a floating point number.
Your problem has nothing to do with Floating, but with the fact that you want to compose a function with two arguments and a function with one argument in a way that doesn't typecheck. I'll give you an example in terms of a composed function reverse . foldr (:) [].
reverse . foldr (:) [] has the type [a] -> [a] and works as expected: it returns a reversed list (foldr (:) [] is essentially id for lists).
However reverse . foldr (:) doesn't type check. Why?
When types match for function composition
Let's review some types:
reverse :: [a] -> [a]
foldr (:) :: [a] -> [a] -> [a]
foldr (:) [] :: [a] -> [a]
(.) :: (b -> c) -> (a -> b) -> a -> c
reverse . foldr (:) [] typechecks, because (.) instantiates to:
(.) :: ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
In other words, in type annotation for (.):
a becomes [a]
b becomes [a]
c becomes [a]
So reverse . foldr (:) [] has the type [a] -> [a].
When types don't match for function composition
reverse . foldr (:) doesn't type check though, because:
foldr (:) :: [a] -> [a] -> [a]
Being the right operant of (.), it would instantiate its type from a -> b to [a] -> ([a] -> [a]). That is, in:
(b -> c) -> (a -> b) -> a -> c
Type variable a would be replaced with [a]
Type variable b would be replaced with [a] -> [a].
If type of foldr (:) was a -> b, the type of (. foldr (:)) would be:
(b -> c) -> a -> c`
(foldr (:) is applied as a right operant to (.)).
But because type of foldr (:) is [a] -> ([a] -> [a]), the type of (. foldr (:)) is:
(([a] -> [a]) -> c) -> [a] -> c
reverse . foldr (:) doesn't type check, because reverse has the type [a] -> [a], not ([a] -> [a]) -> c!
Owl operator
When people first learn function composition in Haskell, they learn that when you have the last argument of function at the right-most of the function body, you can drop it both from arguments and from the body, replacing or parentheses (or dollar-signs) with dots. In other words, the below 4 function definitions are equivalent:
f a x xs = g ( h a ( i x xs))
f a x xs = g $ h a $ i x xs
f a x xs = g . h a . i x $ xs
f a x = g . h a . i x
So people get an intuition that says “I just remove the right-most local variable from the body and from the arguments”, but this intuition is faulty, because once you removed xs,
f a x = g . h a . i x
f a = g . h a . i
are not equivalent! You should understand when function composition typechecks and when it doesn't. If the above 2 were equivalent, then it would mean that the below 2 are also equivalent:
f a x xs = g . h a . i x $ xs
f a x xs = g . h a . i $ x xs
which makes no sense, because x is not a function with xs as a parameter. x is a parameter to function i, and xs is a parameter to function (i x).
There is a trick to make a function with 2 parameters point-free. And that is to use an “owl” operator:
f a x xs = g . h a . i x xs
f a = g . h a .: i
where (.:) = (.).(.)
The above two function definitions are equivalent. Read more on “owl” operator.
References
Haskell programming becomes much easier and straightforward, once you understand functions, types, partial application and currying, function composition and dollar-operator. To nail these concepts, read the following StackOverflow answers:
On types and function composition
On higher-order functions, currying, and function composition
On Haskell type system
On point-free style
On const
On const, flip and types
On curry and uncurry
Read also:
Haskell: difference between . (dot) and $ (dollar sign)
Haskell function composition (.) and function application ($) idioms: correct use
I want to realize something like
fun1 f a_ziplist
for example
getZipList $ (\x y z -> x*y+z) <$> ZipList [4,7] <*> ZipList [6,9] <*> ZipList [5,10]
f = (\x y z -> x*y+z)
ziplist = [[4,7],[6,9],[5,10]]
To do this, I want to recursively apply <*> like
foldx (h:w) = h <*> foldx w
foldx (w:[]) = w
but it seems impossible to make <*> recursive.
Let's play with the types in ghci, to see where they carry us.
λ import Control.Applicative
The type of (<*>)
λ :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
The type of foldr:
λ :t Prelude.foldr
Prelude.foldr :: (a -> b -> b) -> b -> [a] -> b
Perhaps we could use (<*>) as the function that is passed as the first parameter of foldr. What would be the type?
λ :t Prelude.foldr (<*>)
Prelude.foldr (<*>) :: Applicative f => f a -> [f (a -> a)] -> f a
So it seems that it takes an initial value in an applicative context, and a list of functions in an applicative context, and returns another applicative.
For example, using ZipList as the applicative:
λ getZipList $ Prelude.foldr (<*>) (ZipList [2,3]) [ ZipList [succ,pred], ZipList [(*2)] ]
The result is:
[5]
I'm not sure if this is what the question intended, but it seems like a natural way to fold using (<*>).
If the ziplist argument has to be a plain list, it looks impossible. This is because fold f [a1,...,an] must be well typed for every n, hence f must be a function type taking at least n arguments for every n, hence infinitely many.
However, if you use a GADT list type, in which values expose their length as a type-level natural you can achieve something similar to what you want.
{-# LANGUAGE DataKinds, KindSignatures, TypeFamilies, GADTs #-}
import Control.Applicative
-- | Type-level naturals
data Nat = Z | S Nat
-- | Type family for n-ary functions
type family Fn (n :: Nat) a b
type instance Fn Z a b = b
type instance Fn (S n) a b = a -> Fn n a b
-- | Lists exposing their length in their type
data List a (n :: Nat) where
Nil :: List a Z
Cons :: a -> List a n -> List a (S n)
-- | General <*> applied to a list of arguments of the right length
class Apply (n :: Nat) where
foldF :: Applicative f => f (Fn n a b) -> List (f a) n -> f b
instance Apply Z where
foldF f0 Nil = f0
instance Apply n => Apply (S n) where
foldF fn (Cons x xs) = foldF (fn <*> x) xs
test :: [(Integer,Integer,Integer)]
test = foldF (pure (,,)) (Cons [10,11] (Cons [20,21] (Cons [30,31] Nil)))
-- Result: [(10,20,30),(10,20,31),(10,21,30),(10,21,31)
-- ,(11,20,30),(11,20,31),(11,21,30),(11,21,31)]
In general folding (<*>) is tricky because of types, as others have mentioned. But for your specific example, where your ziplist elements are all of the same type, you can use a different method and make your calculation work with a small change to f to make it take a list argument instead of single elements:
import Data.Traversable
import Control.Applicative
f = (\[x,y,z] -> x*y+z)
ziplist = [[4,7],[6,9],[5,10]]
fun1 f l = getZipList $ f <$> traverse ZipList l
It's even possible to achieve this with just Data.List and Prelude functions:
fun1 f = map f . transpose
To do this, I want to recursively apply <*> like
foldx (h:w) = h <*> foldx w
foldx (w:[]) = w
but it seems impossible to make <*> recursive.
I think you're getting confused over left- vs. right-associativity. danidiaz reformulates this in terms of foldr (<*>), which is quite useful for this analysis. The documentation gives a useful definition of foldr in terms of expansion:
foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z) ...)
So applying that to your case:
foldr (<*>) z [x1, x2, ..., xn] == x1 <*> (x2 <*> ... (xn <*> z) ...)
Note the parens. <*> is left-associative, so the foldr expansion is different from:
x1 <*> x2 <*> ... <*> xn <*> z == ((... (x1 <*> x2) <*> ...) <*> xn) <*> z
Let's think also a bit more about what foldr (<*>) means. Another way of thinking of this is to rewrite it just slightly:
flip (foldr (<*>)) :: Applicative f :: [f (a -> a)] -> f a -> f a
Types of the form (a -> a) are often called endomorphisms, and they form a monoid, with composition as the operation and id as the identity. There's a newtype wrapper in Data.Monoid for these:
newtype Endo a = Endo { appEndo :: a -> a }
instance Monoid (Endo a) where
mempty = id
mappend = (.)
This gives us yet another way to think of foldr (<*>), by formulating it in terms of Endo:
toEndo :: Applicative f => f (a -> a) -> Endo (f a)
toEndo ff = Endo (ff <*>)
And then what foldr (<*>) does, basically, is reduce this monoid:
foldrStar :: Applicative f => [f (a -> a)] -> Endo (f a)
foldrStar fs = mconcat $ map toMonoid fs
what you have is equivalent to zipWith3 (\x y z -> x*y+z) [4,7] [6,9] [5,10].
it's impossible to foldl the <*> (and you do need foldl as <*> associates to the left) because foldl :: (a -> b -> a) -> a -> [b] -> a i.e. it's the same a in a -> b -> a, but when you apply your ternary function on first list of numbers, you get a list of binary functions, and then unary functions at the next step, and only finally, numbers (all different types, then):
>> let xs = map ZipList [[4,7],[6,9],[5,10]]
>> getZipList $ pure (\x y z -> x*y+z) <*> (xs!!0) <*> (xs!!1) <*> (xs!!2)
[29,73]
>> foldl (<*>) (pure (\x y z -> x*y+z)) xs
<interactive>:1:6:
Occurs check: cannot construct the infinite type: b = a -> b
Expected type: f (a -> b)
Inferred type: f b
In the first argument of `foldl', namely `(<*>)'
In the expression: foldl (<*>) (pure (\ x y z -> x * y + z)) xs
>> :t foldl
foldl :: ( a -> b -> a ) -> a -> [b] -> a
>> :t (<*>)
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b -- f (a -> b) = f b
The answer by chi addresses this, but the arity is fixed (for a particular code). In effect, what that answer really does is defining (a restricted version of) zipWithN (well, here, when used with the ZipList applicative - obviously, it works with any applicative in general) for any N (but just for the a -> a -> a -> ... -> a type of functions), whereas e.g.
zipWith7 :: (a -> b -> c -> d -> e -> f -> g -> h) ->
[a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g] -> [h]
(in other words, zipWith3 (,,) [10,11] ([20,21]::[Integer]) ([30,31]::[Int]) works).
I know one can do:
any (>3) [1,2,3,4,5]
but what is the elegant way of implementing:
any and[(>3),(<5)] [1,2,3,4,5]
or
all or[(<2),(>4)] [1,2,3,4,5]
etc?
I believe you'd like to check whether there are any elements that are both (<5) and (>3).
You can do that this way:
any (\x -> x > 3 && x < 5) [1..5]
and your the other one can be done by
any (\x -> x < 2 || x > 4) [1..5]
But maybe it would be more fun to define && and || to work on functions:
infixr 3 &&&
infixr 3 |||
(&&&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
(f &&& g) x = f x && g x
(|||) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
(f ||| g) x = f x || g x
so now we can rewrite your examples as:
any ((>3) &&& (<5)) [1..5]
any ((<2) ||| (>4)) [1..5]
Your notation and[(>3),(<5)] can be almost directly implemented as a higher order function. I'll call it andP, since any takes a predicate and a list of values, and we want a function that takes a list of predicates.
andP :: [a -> Bool] -> a -> Bool
andP ps x = all ($ x) ps
Now
andP [(>3), (<5)] x = x > 3 && x < 5
and you can write as in your initial request as
any (andP [(>3), (<5)]) [1,2,3,4,5]
As a side note, for this particular example, I think a clearer way would be:
between :: (Ord a) => a -> a -> a -> Bool
between lo hi x = lo < x && x < hi
any (between 3 5) [1,2,3,4,5]
Another approach is to use Monoids. Bool is a Monoid when wrapped in All or Any from Data.Monoid. We need that because there are two ways to combine [Bool] - we can either use && or ||. That's why there are the types All :: Bool -> All and Any :: Bool -> Any which are instances of Monoid. For example:
> import Data.Monoid
> getAll $ mconcat [All True, All True, All False]
False
> getAll $ mconcat [All True, All True, All True]
True
> getAny $ mconcat [Any True, Any True, Any False]
True
The other fact that we use is the Monoid instance for functions (again from Data.Monoid):
instance Monoid b => Monoid (a -> b) where
mempty _ = mempty
mappend f g x = f x `mappend` g x
Now we can append functions:
> :t All
All :: Bool -> All
> :t (<5)
(<5) :: (Num a, Ord a) => a -> Bool
> :t All . (<5)
All . (<5) :: (Num a, Ord a) => a -> All
> :t ((All . (<5)) <> (All . (>3)))
((All . (<5)) <> (All . (>3))) :: (Num a, Ord a) => a -> All
> getAll $ ((All . (<5)) <> (All . (>3))) 4
True
Generalizing this to lists of functions:
> getAll $ mconcat [(All. (<5)), (All . (>3))] $ 4
True
> getAll $ mconcat (map (All .) [(<5), (>3)]) $ 4
True
Then searching http://www.haskell.org/hoogle/ for (a->b) -> [a] -> b we see foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m which we can use instead of mconcat . map:
> import Data.Foldable
> getAll $ foldMap (All .) [(<5), (>3)] $ 4
True
And finally mapping it over a list of numbers:
> map (getAll . foldMap (All .) [(<5), (>3)]) $ [1..5]
[False,False,False,True,False]
> Prelude.or $ map (getAll . foldMap (All .) [(<5), (>3)]) $ [1..5]
True
You can also define an operator that takes a list of predicates by employing some Monoid instances as follows.
test = any (andP [(>3),(<5)]) [1,2,3,4,5]
andP :: [a -> Bool] -> a -> Bool
andP ps = getAll . mconcat (map (All.) ps)