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

Его экземпляр класса >Monad похож на экземпляр для типа >Maybe и может быть обнаружен в модуле >Control.Monad.Error[15]:

>instance (Error e) => Monad (Either e) where

>   return x = Right x

>   Right x >>= f = f x

>   Left err >>= f = Left err

>   fail msg = Left (strMsg msg)

Функция >return, как и всегда, принимает значение и помещает его в минимальный контекст по умолчанию. Она оборачивает наше значение в конструктор >Right, потому что мы используем его для представления успешных вычислений, где присутствует результат. Это очень похоже на определение метода >return для типа >Maybe.

Оператор >>>= проверяет два возможных случая: >Left и >Right. В случае >Right к значению внутри него применяется функция >f, подобно случаю >Just, где к его содержимому просто применяется функция. В случае ошибки сохраняется значение >Left вместе с его содержимым, которое описывает неудачу.

Экземпляр класса >Monad для типа >Either e имеет дополнительное требование. Тип значения, содержащегося в >Left, – тот, что указан параметром типа >e, – должен быть экземпляром класса >Error. Класс >Error предназначен для типов, значения которых могут действовать как сообщения об ошибках. Он определяет функцию >strMsg, которая принимает ошибку в виде строки и возвращает такое значение. Хороший пример экземпляра >Error – тип >String! В случае со >String функция >strMsg просто возвращает строку, которую она получила:

>ghci> :t strMsg

>strMsg :: (Error a) => String –> a

>ghci> strMsg "Бум!" :: String

>"Бум!"

Но поскольку при использовании типа >Either для описания ошибки мы обычно задействуем тип >String, нам не нужно об этом сильно беспокоиться. Когда сопоставление с образцом терпит неудачу в нотации >do, то для оповещения об этой неудаче используется значение >Left.

Вот несколько практических примеров:

>ghci> Left "Бум" >>= \x –>return (x+1)

>Left "Бум"

>ghci> Left "Бум " >>= \x –> Left "нет пути!"

>Left "Бум "

>ghci> Right 100 >>= \x –> Left "нет пути!"

>Left "нет пути!"

Когда мы используем операцию >>>=, чтобы передать функции значение >Left, функция игнорируется и возвращается идентичное значение >Left. Когда мы передаём функции значение >Right, функция применяется к тому, что находится внутри, но в данном случае эта функция всё равно произвела значение >Left!

Использование монады >Error очень похоже на использование монады >Maybe.

ПРИМЕЧАНИЕ. В предыдущей главе мы использовали монадические аспекты типа >Maybe для симуляции приземления птиц на балансировочный шест канатоходца. В качестве упражнения вы можете переписать код с использованием монады >Error, чтобы, когда канатоходец поскальзывался и падал, вы запоминали, сколько птиц было на каждой стороне шеста в момент падения.