и
>1
в стек, а затем выполняется выражение
>push 10
, проталкивая число
>10
на верхушку.
Реализация для функции >join
такова:
>join :: (Monad m) => m (m a) –> m a
>join mm = do
> m <– mm
> m
Поскольку результат >mm
является монадическим значением, мы берём этот результат, а затем просто помещаем его на его собственную строку, потому что это и есть монадическое значение. Трюк здесь в том, что когда мы вызываем выражение >m
><–
>mm
, контекст монады, в которой мы находимся, будет обработан. Вот почему, например, значения типа >Maybe
дают в результате значения >Just
, только если и внешнее, и внутреннее значения являются значениями >Just
. Вот как это выглядело бы, если бы значение >mm
было заранее установлено в >Just (Just 8)
:
>joinedMaybes :: Maybe Int
>joinedMaybes = do
> m <– Just (Just 8)
> m
Наверное, самое интересное в функции >join
– то, что для любой монады передача монадического значения в функцию с помощью операции >>>=
представляет собой то же самое, что и просто отображение значения с помощью этой функции, а затем использование функции >join
для разглаживания результирующего вложенного монадического значения! Другими словами, выражение >m >>= f
– всегда то же самое, что и >join (fmap f m)
. Если вдуматься, это имеет смысл.
При использовании операции >>>=
мы постоянно думаем, как передать монадическое значение функции, которая принимает обычное значение, а возвращает монадическое. Если мы просто отобразим монадическое значение с помощью этой функции, то получим монадическое значение внутри монадического значения. Например, скажем, у нас есть >Just 9
и функция >\x –> Just (x+1)
. Если с помощью этой функции мы отобразим >Just 9
, у нас останется >Just (Just 10)
.
То, что выражение >m >>= f
всегда равно >join (fmap f m)
, очень полезно, если мы создаём свой собственный экземпляр класса >Monad
для некоего типа. Это связано с тем, что зачастую проще понять, как мы бы разгладили вложенное монадическое значение, чем понять, как реализовать операцию >>>=
.
Ещё интересно то, что функция >join
не может быть реализована, всего лишь используя функции, предоставляемые функторами и аппликативными функторами. Это приводит нас к заключению, что монады не просто сопоставимы по своей силе с функторами и аппликативными функторами – они на самом деле сильнее, потому что с ними мы можем делать больше, чем просто с функторами и аппликативными функторами.