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)
Related
I am having some troubles with function composition and types.
I would like to compose filter (which returns a list) with len, which takes a list as an argument (technically a Foldable but I am simplifying here).
Looking at the types everything is as expected:
> :t length
length :: Foldable t => t a -> Int
> :t filter
filter :: (a -> Bool) -> [a] -> [a]
So now I would expect the type of (len . filter) to be
(length . filter) :: (a -> Bool) -> [a] -> Int
while in reality is
> :t (length . filter)
(length . filter) :: Foldable ((->) [a]) => (a -> Bool) -> Int
So it seems I lost some arguments. Is it included in the the Foldable requirements in some way I am not understanding?
Note that everything works as expected if I do partial application:
> let myFilter = filter odd
> :t myFilter
myFilter :: Integral a => [a] -> [a]
> :t (length . myFilter)
(length . myFilter) :: Integral a => [a] -> Int
> (length . myFilter) [1,2,3]
2
The right composition would be:
(length .) . filter :: (a -> Bool) -> [a] -> Int
which is equivalent to:
\pred xs -> length $ filter pred xs
as in:
\> let count = (length .) . filter
\> :type count
count :: (a -> Bool) -> [a] -> Int
\> count odd [1..3]
2
\> count even [1..3]
1
Definitions:
(.) :: (b -> c) -> (a -> b) -> a -> c
filter :: (m -> Bool) -> [m] -> [m]
length :: Foldable t => t n -> Int
What is u?
length . filter :: u
≡ (.) length filter :: u
Then we must solve a, b, c, t, n:
a -> b ~ (m -> Bool) -> [m] -> [m]
b -> c ~ Foldable t => t n -> Int
It follows:
a ~ m -> Bool
b ~ Foldable t => t n
b ~ [m] -> [m]
c ~ Int
Trivially:
a = m -> Bool
b = [m] -> [m]
c = Int
We have to solve t, n from b ~ Foldable t => t n, i.e. [m] -> [m] ~ Foldable t => t n.
t = ((->) [m])
n = [m]
Therefore, t n = [m] -> [m] which trivially unifies.
Summarising:
(.) :: Foldable ((->) [m]) =>
(([m] -> [m]) -> Int)
-> ((m -> Bool) -> [m] -> [m])
-> (m -> Bool) -> Int
filter :: (m -> Bool) -> [m] -> [m]
length :: Foldable ((->) [m]) => ([m] -> [m]) -> Int
(.) length filter :: Foldable ((->) [m]) => (m -> Bool) -> Int
An easier way to understand why length . filter is not what you want is to look at the definition of (.).
(.) g f x = g(f x)
Therefore:
(.) length filter
≡ \x -> length (filter x)
We know that filter x is not a list.
Pointless versions you may consider:
(length .) . filter
filter >=> return . length
(fmap.fmap) length filter
(id ~> id ~> length) filter -- [1]
filter $* id $$ id *$ length -- [2]
lurryA #N2 (length <$> (filter <$> _1 <*> _2)) -- [3]
Control.Compose
Data.Function.Meld
Data.Function.Tacit
Using "three laws of operator sections", we have
((length .) . filter) x y =
(length .) (filter x) y =
(length . filter x) y =
length (filter x y)
and
((length .) . filter) =
(.) (length .) filter =
(.) ((.) length) filter =
((.) . (.)) length filter
The last bit, ((.).(.)), is sometimes known as "owl operator", also written as .: (length .: filter), or fmap . fmap (for functions, fmap is (.)).
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'm trying to write something like this in Haskell:
length . nub . intersect
but it doesn't work.
*Main Data.List> :t intersect
intersect :: Eq a => [a] -> [a] -> [a]
*Main Data.List> :t nub
nub :: Eq a => [a] -> [a]
*Main Data.List> :t length
length :: [a] -> Int
Based on the type, my understanding is that intersect returns a type of [a] and donates to nub , which takes exactly a type of [a] , then also returns a type of [a] to length , then finally the return should be an Int. What's wrong with it?
The problem here is that intersect takes 2 arguments (in a sense)
you can provide one of the arguments explicitly:
> let f a = length . nub . intersect a
> :t f
f :: Eq a => [a] -> [a] -> Int
or you can use a fun little operator like (.:) = (.) . (.):
> let (.:) = (.) . (.)
> :t length .: (nub .: intersect)
length .: (nub .: intersect) :: Eq a => [a] -> [a] -> Int
here is a version where you don't need the parens:
import Data.List
infixr 9 .:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.).(.)
f :: Eq a => [a] -> [a] -> Int
f = length .: nub .: intersect
I guess this is based on the comments in your previous question, where #CarstenKönig mentions (.) . (.).
First of all, length . nub . intersect cannot work. Your types are:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
length :: [a] -> Int
nub :: Eq a => [a] -> [a]
intersect :: Eq a => [a] -> [a] -> [a] ~ [a] -> ([a] -> [a])
As you can see, intersect has the wrong type, in the context of (.), the type parameter b would be replaced by ([a] -> [a]), which isn't the type of nub's first argument.
I'd say this: write your code the "dumb" way at first, and then refactor it to use (.). After some practice the composition operator will then become like second nature.
So you'd first write:
yourFunction xs ys = length (nub (intersect xs ys))
What (.) lets you do is get rid (syntactically) of the last argument of the innermost function, all all the parens. In this case that argument is ys:
yourFunction xs = length . nub . intersect xs
What is a good way to represent the type LoL a, being a list of lists
of ... of a? The nesting level is arbitrary, but uniform over all
elements of the outer list.
The case I have in mind is to apply a grouping on the members of a
list, and then to apply a next grouping on each subgroup, and so on. It
is not known up front how many groupings one will have to apply. Hence:
rGroupBy :: [(a -> a -> Bool)] -> [a] -> [...[a]...]
Extra brownie points for the type signature of rGroupBy ;-)
Example:
Suppose deweyGroup i groups the elements based on the i-th number
rGroupBy [deweyGroup 1, deweyGroup 2]
["1.1", "1.2.1", "1.2.2", "2.1", "2.2", "3"]
gives:
[ [ [ "1.1" ], [ "1.2.1", "1.2.2" ] ],
[ [ "2.1" ], [ "2.2" ] ],
[ [ "3" ] ]
]
Postscript
One day later, we have 4 excellent and complementary solutions. I'm very pleased with the answers; thank you all.
Another way to enforce the constraint that all branches have equal depth is to use a nested datatype:
data LoL a = One [a] | Many (LoL [a])
mapLoL :: ([a] -> [b]) -> LoL a -> LoL b
mapLoL f (One xs) = One (f xs)
mapLoL f (Many l) = Many $ mapLoL (map f) l
rGroupBy :: [a -> a -> Bool] -> [a] -> LoL a
rGroupBy [] xs = One xs
rGroupBy (f:fs) xs = Many $ mapLoL (groupBy f) $ rGroupBy fs xs
Expanding the definition of LoL, we see that informally,
LoL a = [a] | [[a]] | [[[a]]] | ...
Then we can say, for example:
ghci> rGroupBy [(==) `on` fst, (==) `on` (fst . snd)] [ (i,(j,k)) | i<-[1..3], j<-[1..3], k<-[1..3]]
to get back
Many (Many (One [[[(1,(1,1)),(1,(1,2)),(1,(1,3))]],[[(1,(2,1)),(1,(2,2)),(1,(2,3)), ...
What you actually have is a tree. Try representing it with a recursive data structure:
data LoL a = SoL [a] | MoL [LoL a] deriving (Eq, Show)
rGroupBy :: [(a -> a -> Bool)] -> [a] -> LoL a
rGroupBy (f:fs) = MoL . map (rGroupBy fs) . groupBy f
rGroupBy [] = SoL
deweyGroup :: Int -> String -> String -> Bool
deweyGroup i a b = a!!idx == b!!idx where idx = 2*(i-1)
rGroupBy [deweyGroup 1, deweyGroup 2] ["1.1", "1.2.1", "1.2.2", "2.1", "2.2", "3.0"] gives:
MoL [MoL [SoL ["1.1"],
SoL ["1.2.1","1.2.2"]],
MoL [SoL ["2.1"],
SoL ["2.2"]],
MoL [SoL ["3.0"]]
]
If you want to enforce uniform depth, there is a (fairly) standard trick to do that involving polymorphic recursion. What we'll do is have a spine of "deeper" constructors telling how deeply nested the list is, then a final "here" constructor with the deeply-nested list:
data GroupList a = Deeper (GroupList [a]) | Here a deriving (Eq, Ord, Show, Read)
Actually, the type as defined has one aesthetic choice that you may wish to vary in your code: the Here constructor takes a single a and not a list of as. The consequences of this choice are sort of scattered through the rest of this answer.
Here's an example of a value of this type exhibiting lists-of-lists; it has two Deeper constructors corresponding to the depth-two nesting that it has:
> :t Deeper (Deeper (Here [[1,2,3], []]))
Num a => GroupList a
Here's see a few sample functions.
instance Functor GroupList where
fmap f (Here a ) = Here (f a)
fmap f (Deeper as) = Deeper (fmap (fmap f) as)
-- the inner fmap is at []-type
-- this type signature is not optional
flatten :: GroupList [a] -> GroupList a
flatten (Here a ) = Deeper (Here a)
flatten (Deeper as) = Deeper (flatten as)
singleGrouping :: (a -> a -> Bool) -> GroupList [a] -> GroupList [a]
singleGrouping f = flatten . fmap (groupBy f)
rGroupBy :: [a -> a -> Bool] -> [a] -> GroupList [a]
rGroupBy fs xs = foldr singleGrouping (Here xs) fs
I believe the following example should be close to what you had in mind. First we declare type-level natural numbers. Then we define vectors, which carry their length as a phantom type (see Fixed-length vectors in Haskell, Part 1: Using GADTs). And then we define a structure for nested lists of lists of ... which carries the depth as a phantom type. Finally we can define correctly typed rGroupBy.
{-# LANGUAGE GADTs #-}
{-# LANGUAGE EmptyDataDecls #-}
import Data.List (groupBy)
data Zero
data Succ n
data Vec n a where
Nil :: Vec Zero a
Cons :: a -> Vec n a -> Vec (Succ n) a
data LList n a where
Singleton :: a -> LList Zero a
SuccList :: [LList n a] -> LList (Succ n) a
-- Not very efficient, but enough for this example.
instance Show a => Show (LList n a) where
showsPrec _ (Singleton x) = shows x
showsPrec _ (SuccList lls) = shows lls
rGroupBy :: Vec n (a -> a -> Bool) -> [a] -> LList (Succ n) a
rGroupBy Nil
= SuccList . map Singleton
rGroupBy (Cons f fs)
= SuccList . map (rGroupBy fs) . groupBy f
-- TEST ------------------------------------------------------------
main = do
let input = ["1.1", "1.2.1", "1.2.2", "2.1", "2.2", "3"]
-- don't split anything
print $ rGroupBy Nil input
-- split on 2 levels
print $ rGroupBy (Cons (deweyGroup 1)
(Cons (deweyGroup 2) Nil))
input
where
deweyGroup :: Int -> String -> String -> Bool
deweyGroup i a b = a!!idx == b!!idx where idx = 2*(i-1)
As a type-hackery exercise it is possible to implement this with standard lists.
All we need is an arbitrary depth groupStringsBy function:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts,
UndecidableInstances, IncoherentInstances,
TypeFamilies, ScopedTypeVariables #-}
import Data.List
import Data.Function
class StringGroupable a b where
groupStringBy :: Pred -> a -> b
instance (StringGroupable a b, r ~ [b]) => StringGroupable [a] r where
groupStringBy f = map (groupStringBy f)
instance (r ~ [[String]]) => StringGroupable [String] r where
groupStringBy p = groupBy p
Which works like this:
*Main> let lst = ["11","11","22","1","2"]
*Main> groupStringBy ((==) `on` length) lst
[["11","11","22"],["1","2"]]
*Main> groupStringBy (==) . groupStringBy ((==) `on` length) $ lst
[[["11","11"],["22"]],[["1"],["2"]]]
So we can use this function directly (although it has to be put in reverse order):
inp = ["1.1", "1.2.1", "1.2.2", "2.1", "2.2", "3"]
deweyGroup :: Int -> String -> String -> Bool
deweyGroup i a b = a!!idx == b!!idx where idx = 2*(i-1)
-- gives: [[["1.1"],["1.2.1","1.2.2"]],[["2.1"],["2.2"]],[["3"]]]
test1 = groupStringBy (deweyGroup 2) . groupStringBy (deweyGroup 1) $ inp
But if you want to use your original sample, we can hack it too.
First we need a variable argument function which pipelines all the arguments but the last one in reverse order via . and then applies the resulting function to the last argument:
class App a b c r where
app :: (a -> b) -> c -> r
instance (b ~ c, App a d n r1, r ~ (n -> r1)) => App a b (c -> d) r where
app c f = \n -> app (f . c) n
instance (a ~ c, r ~ b) => App a b c r where
app c a = c a
Works like this:
*Main> app not not not True
False
*Main> app (+3) (*2) 2
10
Then expand it with a custom rule for our predicate type type Pred = String -> String -> Bool:
type Pred = String -> String -> Bool
instance (StringGroupable b c, App a c n r1, r ~ (n -> r1)) => App a b Pred r where
app c p = app ((groupStringBy p :: b -> c) . c)
And finally wrap it in rGroupBy (supplying id function to be the first in the pipeline):
rGroupBy :: (App [String] [String] Pred r) => Pred -> r
rGroupBy p = app (id :: [String] -> [String]) p
Now it should work for any number of grouping predicates of type Pred producing the list of the depth equal to the number of supplied predicates:
-- gives: [["1.1","1.2.1","1.2.2"],["2.1","2.2"],["3"]]
test2 = rGroupBy (deweyGroup 1) inp
-- gives: [[["1.1"],["1.2.1","1.2.2"]],[["2.1"],["2.2"]],[["3"]]]
test3 = rGroupBy (deweyGroup 1) (deweyGroup 2) inp
-- gives: [[[["1.1"]],[["1.2.1","1.2.2"]]],[[["2.1"]],[["2.2"]]],[[["3"]]]]
test4 = rGroupBy (deweyGroup 1) (deweyGroup 2) (deweyGroup 1) inp
So it is possible (and probably can be simplified) but as always with this sort of hackery is not recommended to be used for anything but the exercise.
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)