zoran119
zoran119

Reputation: 11327

Composition of Applicative functions

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

Answers (3)

Benjamin Hodgson
Benjamin Hodgson

Reputation: 44654

{-# LANGUAGE TypeOperators #-}

The (type-level) composition of any two applicative functors,

newtype (f :. g) a = Compose { getCompose :: f (g a)) }

is an applicative functor.

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 like z = 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

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

Gurkenglas
Gurkenglas

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

Related Questions