Результаты оказались такими, каких мы и ждали! Если монадическое значение слева равно Nothing
Nothing
. А если функция справа возвращает значение Nothing
, результатом опять будет Nothing
. Это очень похоже на тот случай, когда мы использовали тип Maybe
в качестве аппликативного функтора и в результате получали значение Nothing
, если где-то в составе присутствовало значение Nothing
.Похоже, мы догадались, как взять причудливое значение, передать его функции, которая принимает обычное значение, и вернуть причудливое значение. Мы сделали это, помня, что значение типа Maybe
Вы можете спросить себя: «Чем это полезно?» Может показаться, что аппликативные функторы сильнее монад, поскольку аппликативные функторы позволяют нам взять обычную функцию и заставить её работать со значениями, имеющими контекст. В этой главе вы увидите, что монады, будучи усовершенствованными аппликативными функторами, тоже способны на такое. На самом деле они могут делать и кое-какие другие крутые вещи, на которые не способны аппликативные функторы.
Мы вернёмся к Maybe
Класс типов Monad
Как и функторы, у которых есть класс типов Functor
Applicative
, монады обладают своим классом типов: Monad
! (Ух ты, кто бы мог подумать?)class Monad m where
return :: a –> m a
(>>=) :: m a –> (a –> m b) –> m b
(>>) :: m a –> m b –> m b
x >> y = x >>= \_ –> y
fail :: String –> m a
fail msg = error msg
В первой строке говорится class Monad m where
class (Applicative m) => Monad m where
, чтобы тип должен был являться аппликативным функтором, прежде чем он может быть сделан монадой? Ладно, положим, надлежит, – но когда появился язык Haskell, людям не пришло в голову, что аппликативные функторы хорошо подходят для этого языка. Тем не менее будьте уверены: каждая монада является аппликативным функтором, даже если в объявлении класса Monad
этого не говорится.Первой функцией, которая объявлена в классе типов Monad
return
. Она аналогична функции pure
, находящейся в классе типов Applicative
. Так что, хоть она и называется по-другому, вы уже фактически с ней знакомы. Функция return
имеет тип (Monad m) => a –> m a
. Она принимает значение и помещает его в минимальный контекст по умолчанию, который по-прежнему содержит это значение. Другими словами, она принимает нечто и оборачивает это в монаду. Мы уже использовали функцию return
при обработке действий ввода-вывода (см. главу 8). Там она понадобилась для получения значения и создания фальшивого действия ввода-вывода, которое ничего не делает, а только возвращает это значение. В случае с типом Maybe
она принимает значение и оборачивает его в конструктор Just
.ПРИМЕЧАНИЕ.
Функцияreturn
ничем не похожа на оператор return
из других языков программирования, таких как C++ или Java. Она не завершает выполнение функции. Она просто принимает обычное значение и помещает его в контекст.Следующей функцией является >>=
Затем у нас есть операция >>
Monad
. Мы подробно рассмотрим её в разделе «Банан на канате».Последним методом в классе типов Monad
fail
. Мы никогда не используем её в нашем коде явно. Вместо этого её использует язык Haskell, чтобы сделать возможным неуспешное окончание вычислений в специальной синтаксической конструкции для монад, с которой вы встретитесь позже. Нам не нужно сейчас сильно беспокоиться по поводу этой функции.Теперь, когда вы знаете, как выглядит класс типов Monad
Maybe
реализован экземпляр этого класса!instance Monad Maybe where
return x = Just x
Nothing >>= f = Nothing
Just x >>= f = f x