Реализация для операции >>>=
может выглядеть немного загадочно, но на самом деле она не так уж и сложна. Когда мы используем операцию >>>=
для передачи монадического значения функции, результатом всегда будет монадическое значение. Так что в данном случае, когда мы передаём функцию другой функции, результатом тоже будет функция. Вот почему результат начинается с анонимной функции.
Все реализации операции >>>=
до сих пор так или иначе отделяли результат от монадического значения, а затем применяли к этому результату функцию >f
. То же самое происходит и здесь. Чтобы получить результат из функции, нам необходимо применить её к чему-либо, поэтому мы используем здесь >(h w)
, а затем применяем к этому >f
. Функция >f
возвращает монадическое значение, которое в нашем случае является функцией, поэтому мы применяем её также и к значению >w
.
Если в данный момент вы не понимаете, как работает операция >>>=
, не беспокойтесь. Несколько примеров позволят вам убедиться, что это очень простая монада. Вот выражение >do
, которое её использует:
>import Control.Monad.Instances
>addStuff :: Int –> Int
>addStuff = do
> a <– (*2)
> b <– (+10)
> return (a+b)
Это то же самое, что и аппликативное выражение, которое мы записали ранее, только теперь оно полагается на то, что функции являются монадами. Выражение >do
всегда возвращает монадическое значение, и данное выражение ничем от него не отличается. Результатом этого монадического значения является функция. Она принимает число, затем к этому числу применяется функция >(*2)
и результат записывается в образец >a
. К тому же самому числу, к которому применялась функция >(*2)
, применяется теперь уже функция >(+10)
, и результат записывается в образец >b
. Функция >return
, как и в других монадах, не имеет никакого другого эффекта, кроме создания монадического значения, возвращающего некий результат. Она возвращает значение выражения >(a+b)
в качестве результата данной функции. Если мы протестируем её, то получим те же результаты, что и прежде:
>ghci> addStuff 3
>19
И функция >(*2)
, и функция >(+10)
применяются в данном случае к числу >3
. Выражение >return (a+b)
применяется тоже, но оно игнорирует это значение и всегда возвращает >(a+b)
в качестве результата. По этой причине функциональную монаду также называют монадой-читателем. Все функции читают из общего источника. Чтобы сделать это ещё очевиднее, мы можем переписать функцию >addStuff
вот так:
>addStuff :: Int –> Int
>addStuff x = let a = (*2) x
> b = (+10) x
> in a+b
Вы видите, что монада-читатель позволяет нам обрабатывать функции как значения с контекстом. Мы можем действовать так, как будто уже знаем, что вернут функции. Суть в том, что монада-читатель «склеивает» функции в одну, а затем передаёт параметр этой функции всем тем, которые её составляют. Поэтому если у нас есть множество функций, каждой из которых недостаёт всего лишь одного параметра, и в конечном счёте они будут применены к одному и тому же, то мы можем использовать монаду-читатель, чтобы как бы извлечь их будущие результаты. А реализация операции