Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boolean operators over multiple elements

Tags:

haskell

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?

like image 625
peroni_santo Avatar asked Nov 30 '22 02:11

peroni_santo


2 Answers

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]
like image 163
AndrewC Avatar answered Dec 10 '22 11:12

AndrewC


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]
like image 27
luqui Avatar answered Dec 10 '22 12:12

luqui