Изучай Haskell во имя добра! (Липовача) - страница 255

Реализация для операции >>>= может выглядеть немного загадочно, но на самом деле она не так уж и сложна. Когда мы используем операцию >>>= для передачи монадического значения функции, результатом всегда будет монадическое значение. Так что в данном случае, когда мы передаём функцию другой функции, результатом тоже будет функция. Вот почему результат начинается с анонимной функции.

Все реализации операции >>>= до сих пор так или иначе отделяли результат от монадического значения, а затем применяли к этому результату функцию >f. То же самое происходит и здесь. Чтобы получить результат из функции, нам необходимо применить её к чему-либо, поэтому мы используем здесь >(h w), а затем применяем к этому >f. Функция >f возвращает монадическое значение, которое в нашем случае является функцией, поэтому мы применяем её также и к значению >w.

Монада Reader

Если в данный момент вы не понимаете, как работает операция >>>=, не беспокойтесь. Несколько примеров позволят вам убедиться, что это очень простая монада. Вот выражение >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

Вы видите, что монада-читатель позволяет нам обрабатывать функции как значения с контекстом. Мы можем действовать так, как будто уже знаем, что вернут функции. Суть в том, что монада-читатель «склеивает» функции в одну, а затем передаёт параметр этой функции всем тем, которые её составляют. Поэтому если у нас есть множество функций, каждой из которых недостаёт всего лишь одного параметра, и в конечном счёте они будут применены к одному и тому же, то мы можем использовать монаду-читатель, чтобы как бы извлечь их будущие результаты. А реализация операции