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 -> (
-> (x1 -> g >>= x2 -> return ((&&) x1 x2)) (f r) r) -- defn of (>>=)
= f g -> (
-> (x1 -> g >>= x2 -> const ((&&) x1 x2)) (f r) r) -- defn of return
= f g -> (
-> (x1 ->
(
-> (x2 -> const ((&&) x1 x2)) (g r) r)) (f r) r) -- defn of (>>=)
= f g x -> (
-> (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 (&&)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…