The monad laws are traditionally described in terms of >>=
and pure
:
pure a >>= k = k a
m >>= pure = m
m >>= (\x -> k x >>= h) = (m >>= k) >>= h
However, monads can also be defined in terms of join
instead of >>=
. I would like to come up with a formulation of the monad laws in terms of join
.
Using x >>= f = join (fmap f x)
, it’s easy to rewrite the existing monad laws to eliminate >>=
. Simplifying the results slightly with the help of the applicative laws, the first two laws are quite pleasantly expressed:
join . pure = id
join . fmap pure = id
The intuition for these laws is easy, too, since clearly, introducing an extra “layer” with pure
should be a no-op when combined with join
. The third law, however, is not nearly so nice. It ends up looking like this:
join (fmap (\x -> join (fmap h (k x))) m)
= join (fmap h (join (fmap k m)))
This does not pleasantly reduce using the applicative laws, and it’s much harder to understand without staring at it for a while. It certainly doesn’t have the same easy intuition.
Is there an equivalent, alternative formulation of the monad laws in terms of join
that is easier to understand? Alternatively, is there any way to simplify the above law, or to make it easier to grok? The version with >>=
is already less nice than the one expressed with Kleisli composition, but the version with join
is nearly unreadable.
join . pure = join . fmap pure = id
) and the right-hand diagram can be stated asjoin . join = join . fmap join
. Note that(\h k m -> join (fmap h (join (fmap k m)))) id id = \m -> join (join m)
- this follows fromfmap id = id
(and likewise for the other side of the two equalities). In other words, your law expresses both functor and monad laws in one statement.