Actually, in a way, join
is where all the magic really happens--(>>=)
is used mostly for convenience.
All Functor
-based type classes describe additional structure using some type. With Functor
this extra structure is often thought of as a "container", while with Monad
it tends to be thought of as "side effects", but those are just (occasionally misleading) shorthands--it's the same thing either way and not really anything special[0].
The distinctive feature of Monad
compared to other Functor
s is that it can embed control flow into the extra structure. The reason it can do this is that, unlike fmap
which applies a single flat function over the entire structure, (>>=)
inspects individual elements and builds new structure from that.
With a plain Functor
, building new structure from each piece of the original structure would instead nest the Functor
, with each layer representing a point of control flow. This obviously limits the utility, as the result is messy and has a type that reflects the structure of flow control used.
Monadic "side effects" are structures that have a few additional properties[1]:
- Two side effects can be grouped into one (e.g., "do X" and "do Y" become "do X, then Y"), and the order of grouping doesn't matter so long as the order of the effects is maintained.
- A "do nothing" side effect exists (e.g., "do X" and "do nothing" grouped is the same as just "do X")
The join
function is nothing more than that grouping operation: A nested monad type like m (m a)
describes two side effects and the order they occur in, and join
groups them together into a single side effect.
So, as far as monadic side effects are concerned, the bind operation is a shorthand for "take a value with associated side effects and a function that introduces new side effects, then apply the function to the value while combining the side effects for each".
[0]: Except IO
. IO
is very special.
[1]: If you compare these properties to the rules for an instance of Monoid
you'll see close parallels between the two--this is not a coincidence, and is in fact what that "just a monoid in the category of endofunctors, what's the problem?" line is referring to.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…