It is well-known that applicative functors are closed under composition but monads are not. However, I have been having trouble finding a concrete counterexample showing that monads do not always compose.

This answer gives [String -> a] as an example of a non-monad. After playing around with it for a bit, I believe it intuitively, but that answer just says "join cannot be implemented" without really giving any justification. I would like something more formal. Of course there are lots of functions with type [String -> [String -> a]] -> [String -> a]; one must show that any such function necessarily does not satisfy the monad laws.

Any example (with accompanying proof) will do; I am not necessarily looking for a proof of the above example in particular.

The closest I can find is the appendix of web.cecs.pdx.edu/~mpj/pubs/RR-1004.pdf, which shows that under a lot of simplifying assumptions, it is impossible to write join for the composition of two monads in general. But this does not lead to any concrete examples.
–
Brent YorgeyOct 23 '12 at 15:50

You may get better answers to this question on cs.stackexchange.com, the new Computer Science Stack Exchange site.
–
Patrick87Oct 23 '12 at 18:24

2

Perhaps I'm not understanding, but I think the question could be more precisely defined. When you say "composing" two monads, do you mean simply composing the type constructors? And when the result "is not a monad", does this mean that a monad instance of that type construcor cannot be written? And, if a monad instance for the composed type constructor can be written, does it have to bear any relation to the instances of the two factor monads, or can it be totally unrelated?
–
OwenOct 23 '12 at 21:50

1

Yes, I mean composing the type constructors; "not a monad" means a valid (lawful) monad instance cannot be written; and I don't care whether the instance for the composition has any relation to the instances of the factors.
–
Brent YorgeyOct 24 '12 at 23:12

For the definition of return x, we have two choices: B Nothing or B (Just (P x x)). It's clear that in order to have any hope of returning x from (1) and (2), we can't throw away x, so we have to pick the second option.

return' :: a -> Bad a
return' x = B (Just (P x x))

That leaves join. Since there are only a few possible inputs, we can make a case for each:

Thanks, I'm convinced! Though it does make me wonder whether there are ways to simplify your proof.
–
Brent YorgeyOct 25 '12 at 2:07

1

@BrentYorgey: I suspect there should be, as the problems with cases (C) and (D) seem to be very much like the problems you have when trying to define swap :: Pair (Maybe a) -> Maybe (Pair a).
–
hammarOct 25 '12 at 2:20

I claim that if Comp r e were a monad for every r and e then we could realize the law of exluded middle. This is not possible in intuitionistic logic which underlies typesystems of functional languages (having the law of excluded middle is equivalent to having the call/cc operator).

(This is just the swap function from paper Composing monads that Brent mentions, Sect. 4.3, only with newtype's (de)constructors added. Note that we don't care what properties it has, the only important thing is that it is definable and total.)

Conclusion: Even though (->) r and Either r are monads, their composition Comp r r cannot be.

Note: That this is also reflected in how ReaderT and EitherT are defined. BothReaderT r (Either e) and EitherT e (Reader r) are isomorphic to r -> Either e a! There is no way how to define monad for the dual Either e (r -> a).

Escaping IO actions

There are many examples in the same vein that involve IO and which lead to escaping IO somehow. For example:

(I suppose "ap" is a typo in "where fmap, pure and ap are the canonical definitions" (should be <*> instead), tried to edit it but I was told my edit was too short.) --- It's not clear to me that having a definition for join implies a definition for swap. Could you expand on it? The paper referred by Brent seems to imply that to go from join to swap we need the following assumptions: joinM . fmapM join = join . joinM and join . fmap (fmapM joinN ) = fmapM joinN . join where joinM = join :: M, etc.
–
Rafael CaetanoOct 24 '12 at 15:11

1

@RafaelCaetano Thanks for the typo, I fixed it (and also renamed the function to swap to match the paper). I didn't check the paper until now, and you're right, looks like we need J(1) and J(2) to define swap <-> join. This is perhaps a weak spot of my proof and I'll think about it more (maybe it'd be possible to get something from the fact that it's Applicative).
–
Petr PudlákOct 24 '12 at 17:34

@RafaelCaetano But I believe the proof is still valid: If we had join, we could define swap :: (Int -> Maybe a) -> Maybe (Int -> a) using the above definition (no matter what laws this swap satisfies). How would such swap behave? Having no Int, it has nothing to pass to its argument, so it would have to return Nothing for all inputs. I believe we can get a contradiction for join's monad laws without needing to define join from swap back. I'll check it and let you know.
–
Petr PudlákOct 24 '12 at 17:42

@Petr: As it stands I agree with Rafael that this is not quite the proof I am looking for, but I am also curious to see whether it can be fixed along the lines you mention.
–
Brent YorgeyOct 25 '12 at 2:10

1

@PetrPudlák Wow, very nice! Yes, I totally buy it now. These are some really interesting insights. I would not have guessed that simply being able to construct swap could lead to a contradiction, without reference to any of the monad laws at all! If I could accept multiple answers I would accept this one too.
–
Brent YorgeyOct 26 '12 at 14:55

It turns out, ListT m is only a monad if m is a commutative monad. This prevents a large category of monads from composing with [], which breaks the universal rule of "composing two arbitrary monads yields a monad".

I would think this only shows that one specific definition of ListT fails to produce a monad in all cases, rather than showing that no possible definition can work.
–
C. A. McCannOct 23 '12 at 21:08

I don't have to. The negation of "for all this, that" is "there exists a counter-example". The question asked was "for all monads, their composition forms a monad". I have shown a combination of types that are monads on their own, but can't compose.
–
hpcOct 23 '12 at 21:20

10

@hpc, but the composition of two monads is more than the composition of their types. You also need the operations, and my interpretation of Brent's question is that there may not be a methodical way to derive the implementation of the operations -- he is looking for something yet stronger, that some some compositions have no operations satisfying the laws, whether mechanically derivable or not. Does that make sense?
–
luquiOct 23 '12 at 22:03

Yes, luqui has it right. Sorry if my original question was not clear.
–
Brent YorgeyOct 25 '12 at 2:11

What's really missing from this answer is the Monad instance for ListT, and a demonstration that there aren't any others. The statement is "for all this, there exists that" and so the negation is "there exists this such that for all that"
–
Ben MillwoodNov 2 '12 at 11:18