4

Suppose I have two functions

f :: Monad m => a -> m a
g :: a -> a

that I want to consecutively apply to some element like so:

(return x) >>= f >>= g

This doesn't work because g is pure, so I first need to "artificially" turn it monadic. One possibility is

(return x) >>= f >>= (return . g)

which isn't very intuitive to me. Another possibility is to use that a Monad is Applicative:

(return g) <*> ((return x) >>= f)

But this is not very intuitive because of the different order of function and argument:

(>>=) :: Monad m => m a -> (a -> m b) -> m b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b

What is the canonical way to deal with this? If (>>==) = (flip ((<*>) . pure)) one can write ((pure x) >>= f) >>== g, which would be fine except for operator precedence. Of course pure functions in monadic code are a common thing so surely there is a standard way to deal with them?

Edit: I didn't say this originally but I was thinking of a situation where I had several functions, some pure, some monadic, and I wanted to apply them in some random order.

Stefan Witzel
  • 335
  • 2
  • 10

4 Answers4

11

What you here describe is fmap :: Functor f => (a -> b) -> f a -> f b. Furthermore since pure x >>= f should be the same as f x, we thus can simplify the given expression to:

fmap g (f x)

or we can make use of the infix alias (<$>) :: Functor f => (a -> b) -> f a -> f b:

g <$> f x
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
5

I think the most straightforward solution is Kleisli composition >=> from Control.Monad module.

Since both >=> and (.) are right-associative and (.) has higher precedence, you can write the following:

-- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)

f :: Monad m => a -> m a
g :: a -> a
h :: Monad m => a -> m b
j :: b -> b

q :: Monad m => a -> m b
q  =  f >=> return . g >=> h >=> return . j
--       |         |- Use (return .) to transform (a -> b) into (a -> m b)
--       |- Use Kleisli composition >=> to compose Kleisli arrows, i.e.
--       |-   the functions going from values to monadic values, (a -> m b)
Will Ness
  • 70,110
  • 9
  • 98
  • 181
lsmor
  • 4,698
  • 17
  • 38
  • 1
    the functions `a -> m a` are the Kleisli *arrows*; `>=>` and `<=<` are the Kleisli (left-to-right and right-to-left) *composition* operators. – Will Ness Jan 22 '20 at 11:03
  • @WillNess Thanks for the aclaration. Didn't know ;) – lsmor Jan 22 '20 at 11:10
  • 2
    The OP already rejected simply using `return . g` as "unintuitive", but I agree this is a clean approach. Something is only unintuitive until it *becomes* intuitive through repeated use :) – chepner Jan 22 '20 at 13:54
  • 1
    @chepner: yes and having the right precedence helps (which makes your answer helpful). Thanks to Ismor and WillNess. This was all very instructive! – Stefan Witzel Jan 22 '20 at 18:42
4

You can give your (>>==) operator an appropriate precedence to allow the parentheses to be dropped

(>>==) = flip ((<*>) . pure)
infixl 1 >>==

Then

> (>>==) = flip ((<*>) . pure); infixl 1 >>==
> pure 3 >>= (\x -> [x, x]) >>== (+1)
[4,4]
chepner
  • 497,756
  • 71
  • 530
  • 681
1

A solution that I found thanks to @WillemVanOnsems pointer to Control.Monad and that is in the spirit of what I was looking for is to use =<< which has the same argument order as <*> and <$>:

g <$> (f =<< f =<< g <$> g <$> (f =<< y))

where now y is already monadic (say return x). The only thing I am not happy about are the parentheses due to operator precedence.

Stefan Witzel
  • 335
  • 2
  • 10
  • 1
    I find the type diagram [here](https://stackoverflow.com/a/11249714/849891) helpful; you might too. also, "the four types of application" at the bottom [here](https://stackoverflow.com/a/44118041/849891). – Will Ness Jan 22 '20 at 13:39