Reputation: 11327
I can compose pure functions:
let f x = x + 1
let g x = x + 2
let z = f . g
z 1 == 4
I seem to be able to compose monadic functions also:
let f x = Just (x + 1)
let g x = Just (x + 2)
let z x = f x >>= g
z 1 == Just 4
I think I should be able to treat f
and g
from the last example as applicatives and compose those also, just not sure how:
let f x = Just (x + 1)
let g x = Just (x + 2)
let z x = f <*> g -- this doesn't work
z 1 == Just 4
Is this doable?
Bonus points, can z x = f x >>= g
be written as a point-free function? Something like z = f >>= g
?
Upvotes: 2
Views: 1180
Reputation: 44654
{-# LANGUAGE TypeOperators #-}
The (type-level) composition of any two applicative functors,
newtype (f :. g) a = Compose { getCompose :: f (g a)) }
instance (Functor f, Functor g) => Functor (f :. g) where
fmap f = Compose . fmap (fmap f) . getCompose
instance (Applicative f, Applicative g) => Applicative (f :. g) where
pure = Compose . pure . pure
Compose fgf <*> Compose fgx = Compose ((<*>) <$> fgf <*> fgx)
Your example is the composition of the Maybe
applicative with the "function" or "reader" applicative (->) r
.
type ReaderWithMaybe r = ((->) r) :. Maybe
x, y :: ReaderWithMaybe Int Int
x = Compose $ \x -> Just (x + 1)
y = Compose $ \x -> Just (x + 2)
Since ReaderWithMaybe r
is an Applicative
you can do all the usual Applicative
stuff. Here I'm smashing my two values together with +
.
ghci> let z = (+) <$> x <*> y
ghci> getCompose z 3
Just 9 -- (3 + 1) + (3 + 2) == 9
Note that x
and y
both get the same input 3
. That's the behaviour of (->) r
's Applicative
instance. If you want to take the result of f x = Just (x + 1)
and feed it into g x = Just (x + 2)
(to get something equivalent to h x = Just (x + 3)
), well, that's what Monad
is for.
Bonus points, can
z x = f x >>= g
be written as a point-free function? Something likez = f >>= g
?
You can easily define Kleisli composition by hand.
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
f >=> g = \x -> f x >>= g
It happens that >=>
already exists in the standard library, along with its sister <=<
. They are lovingly known as the "fish" operators, and they live in Control.Monad
.
Upvotes: 6
Reputation: 568
Maybe you will be interested by Kleisli composition of monads:
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
Upvotes: 0
Reputation: 2317
Applicative functions aren't
let f x = Just $ x + 1
let g x = Just $ x + 2
, they're
let f = Just $ \x -> x + 1
let g = Just $ \x -> x + 2
. Composition then works like liftA2 (.) f g
or (.) <$> f <*> g
.
Upvotes: 3