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

даже до того, как вообще выяснили, что такое монада!

В этой главе мы узнаем ещё о нескольких монадах. Мы увидим, как они могут сделать наши программы понятнее, позволяя нам обрабатывать все типы значений как монадические значения. Исследование ряда примеров также укрепит наше понимание монад.

Все монады, которые нам предстоит рассмотреть, являются частью пакета mtl. В языке Haskell пакетом является совокупность модулей. Пакет mtl идёт в поставке с Haskell Platform, так что он у вас, вероятно, уже есть. Чтобы проверить, так ли это, выполните команду >ghc-pkg list в командной строке. Эта команда покажет, какие пакеты для языка Haskell у вас уже установлены; одним из таких пакетов должен являться mtl, за названием которого следует номер версии.

Writer? Я о ней почти не знаю!

Итак, мы зарядили наш пистолет монадой >Maybe, списковой монадой и монадой >IO. Теперь давайте поместим в патронник монаду >Writer и посмотрим, что произойдёт, когда мы выстрелим ею!

Между тем как >Maybe предназначена для значений с добавленным контекстом неуспешно оканчивающихся вычислений, а список – для недетерминированных вычислений, монада >Writer предусмотрена для значений, к которым присоединено другое значение, ведущее себя наподобие журнала. Монада >Writer позволяет нам производить вычисления, в то же время обеспечивая слияние всех журнальных значений в одно, которое затем присоединяется к результату.

Например, мы могли бы снабдить наши значения строками, которые объясняют, что происходит, возможно, для отладочных целей. Рассмотрите функцию, которая принимает число бандитов в банде и сообщает нам, является ли эта банда крупной. Это очень простая функция:

>isBigGang :: Int –> Bool

>isBigGang x = x > 9

Ну а что если теперь вместо возвращения значения >True или >False мы хотим, чтобы функция также возвращала строку журнала, которая сообщает, что она сделала? Что ж, мы просто создаём эту строку и возвращаем её наряду с нашим значением >Bool:

>isBigGang :: Int –> (Bool, String)

>isBigGang x = (x > 9, "Размер банды сравнён с 9.")

Так что теперь вместо того, чтобы просто вернуть значение типа >Bool, мы возвращаем кортеж, первым компонентом которого является само значение, а вторым компонентом – строка, сопутствующая этому значению. Теперь у нашего значения появился некоторый добавленный контекст. Давайте опробуем функцию:

>ghci> isBigGang 3

>(False,"Размер банды сравнён с 9.")

>ghci> isBigGang 30

>(True,"Размер банды сравнён с 9.")

Пока всё нормально. Функция >isBigGang принимает нормальное значение и возвращает значение с контекстом. Как мы только что увидели, передача ей нормального значения не составляет сложности. Теперь предположим, что у нас уже есть значение, у которого имеется журнальная запись, присоединённая к нему – такая как