I just wrote the following two functions:
fand :: (a -> Bool) -> (a -> Bool) -> a -> Bool fand f1 f2 x = (f1 x) && (f2 x) f_or :: (a -> Bool) -> (a -> Bool) -> a -> Bool f_or f1 f2 x = (f1 x) || (f2 x)
They might be used to combined the values of two boolean functions such as:
import Text.ParserCombinators.Parsec import Data.Char nameChar = satisfy (isLetter `f_or` isDigit)
After looking at these two functions, I came to the realization that they are very useful. so much so that I now suspect that they are either included in the standard library, or more likely that there is a clean way to do this using existing functions.
What was the "right" way to do this?
The Haskell Report gives a full listing of the Prelude which serves as a spec. And it's perfectly alright to care about this, since (&&) can be used to combine a simple & quick test with one that requires intensive computation.
Or operator is represented by using the '||' double pipe symbol in Haskell. Also, it is an in-built operator available in Haskell, we don't require to include anything to use this while programming.
Description: The boolean type Bool is an enumeration. The basic boolean functions are (&&) (and), (||) (or), and not. The name is defined as True to make guarded expressions more readable.
The == is an operator for comparing if two things are equal. It is quite normal haskell function with type "Eq a => a -> a -> Bool". The type tells that it works on every type of a value that implements Eq typeclass, so it is kind of overloaded.
One simplification,
f_and = liftM2 (&&) f_or = liftM2 (||)
or
= liftA2 (&&) = liftA2 (||)
in the ((->) r)
applicative functor.
Applicative version
Why? We have:
instance Applicative ((->) a) where (<*>) f g x = f x (g x) liftA2 f a b = f <$> a <*> b (<$>) = fmap instance Functor ((->) r) where fmap = (.)
So:
\f g -> liftA2 (&&) f g = \f g -> (&&) <$> f <*> g -- defn of liftA2 = \f g -> ((&&) . f) <*> g -- defn of <$> = \f g x -> (((&&) . f) x) (g x) -- defn of <*> - (.) f g = \x -> f (g x) = \f g x -> ((&&) (f x)) (g x) -- defn of (.) = \f g x -> (f x) && (g x) -- infix (&&)
Monad version
Or for liftM2
, we have:
instance Monad ((->) r) where return = const f >>= k = \ r -> k (f r) r
so:
\f g -> liftM2 (&&) f g = \f g -> do { x1 <- f; x2 <- g; return ((&&) x1 x2) } -- defn of liftM2 = \f g -> f >>= \x1 -> g >>= \x2 -> return ((&&) x1 x2) -- by do notation = \f g -> (\r -> (\x1 -> g >>= \x2 -> return ((&&) x1 x2)) (f r) r) -- defn of (>>=) = \f g -> (\r -> (\x1 -> g >>= \x2 -> const ((&&) x1 x2)) (f r) r) -- defn of return = \f g -> (\r -> (\x1 -> (\r -> (\x2 -> const ((&&) x1 x2)) (g r) r)) (f r) r) -- defn of (>>=) = \f g x -> (\r -> (\x2 -> const ((&&) (f x) x2)) (g r) r) x -- beta reduce = \f g x -> (\x2 -> const ((&&) (f x) x2)) (g x) x -- beta reduce = \f g x -> const ((&&) (f x) (g x)) x -- beta reduce = \f g x -> ((&&) (f x) (g x)) -- defn of const = \f g x -> (f x) && (g x) -- inline (&&)
Totally ripping off of TomMD, I saw the and . map
and or . map
and couldn't help but want to tweak it:
fAnd fs x = all ($x) fs fOr fs x = any ($x) fs
These read nicely I think. fAnd
: are all functions in the list True
when x
is applied to them? fOr
: are any functions in the list True
when x
is applied to them?
ghci> fAnd [even, odd] 3 False ghci> fOr [even, odd] 3 True
fOr is an odd name choice, though. Certainly a good one to throw those imperative programmers for a loop. =)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With