With monads, can join be defined in terms of bind?
In Haskell, monads are defined in terms of the functions return and bind, where return has type a -> ma
and bind has type ma -> (a -> mb) -> mb
. It's been pointed out before that monads can also be defined in terms of return and join, where join is a function with type m (ma) -> ma
. Bind can be defined in terms of join, but is the reverse possible? Can join be defined in terms of bind?
Without join, I have no idea what I'd do if I ever somehow got ahold of a "twice wrapped" monadic value, m (ma)
- none of the functor or monad operations "remove any layers", so to speak. If this isn't possible, why do Haskell and many other monad implementations define them in terms of bind? It seems strictly less useful than a join-based definition.
It is possible:
join :: Monad m => m (m a) -> m a
join m = (m >>= id)
Note the tricky instantiation of >>=
:
(>>=) :: m b -> (b -> m c) -> m c
-- choosing b ~ m a , c ~ a
(>>=) :: m (m a) -> (m a -> m a) -> m a
so we can correctly choose id
for the second argument.
是的,这很简单:
join m = m >>= id
Bind ( >>=
) does in fact "remove a layer":
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Intuitively it "gets some a
s out of the ma
", and feeds then to the a -> mb
function, and then produces a single mb
from the results.
People usually say that it requires the function argument to wrap up its output again in m
, but that's not actually the case. It requires the function's output to be something wrapped up in m
, but it doesn't matter where the wrapping came from.
In the case of implementing join
we're starting from something "double-wrapped": m (ma)
. We can plug that into the signature for bind and immediately figure out the type of function we could use when binding a "double-wrapped" value:
m (m a) -> (m a -> m b) -> m b
Now the function used with bind here is going to receive a value that's already wrapped in m
. So we don't have to "re-wrap" anything; if we return it unmodified it'll already be the right type for the output. Effectively that's "removed one layer of wrapping" - and this works for any layer but the last one.
So that tells us we just have to bind with id
:
join = (>>= id)
链接地址: http://www.djcxy.com/p/33224.html
上一篇: 如何升级堆栈ghc