join
is just implemented as [src]:
join :: (Monad m) => m (m a) -> m a
join x = x >>= id
If we take a look at the monad instances of []
[src] and Maybe
[src], we see:
instance Monad [] where
{-# INLINE (>>=) #-}
xs >>= f = [y | x <- xs, y <- f x]
{-# INLINE (>>) #-}
(>>) = (*>)
{-# INLINE fail #-}
fail _ = []
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
(>>) = (*>)
fail _ = Nothing
So that means that for lists, join
is equivalent to:
-- for lists
join xs
-> xs >>= id
-> [ y | x <- xs, y <- id x ]
-> concatMap id xs
-> concat xs
so for lists, the equivalent implementation is:
join_list :: [[a]] -> [a]
join_list = concat
For Maybe
we can do case-analysis: the input is a Maybe (Maybe a)
so there are basically three possibilities here:
-- (1)
join Nothing
-> Nothing >>= id
-> Nothing
-- (2)
join (Just Nothing)
-> Just Nothing >>= id
-> id Nothing
-> Nothing
-- (3)
join (Just (Just x))
-> Just (Just x) >>= id
-> id (Just x)
-> Just x
So that means that for Maybe
s the equivalent implementation is:
join_maybe :: Maybe (Maybe a) -> Maybe a
join_maybe (Just x) = x
join_maybe Nothing = Nothing
join
is thus not reimplemented for list or Maybe
monads, it simply uses the implementation for (>>=)
for lists and Maybe
s, and since these differ, the behavior of join
is of course different.