, поскольку нам не к чему применить эту функцию.
Мы не смогли бы достигнуть этого, просто используя >Maybe
в качестве аппликативного функтора. Если вы попробуете так сделать, то застрянете, поскольку аппликативные функторы не очень-то позволяют аппликативным значениям взаимодействовать друг с другом. Их в лучшем случае можно использовать как параметры для функции, применяя аппликативный стиль.
Аппликативные операторы извлекут свои результаты и передадут их функции в соответствующем для каждого аппликативного функтора виде, а затем соберут окончательное аппликативное значение, но взаимодействие между ними не особенно заметно. Здесь, однако, каждый шаг зависит от результата предыдущего шага. Во время каждого приземления возможный результат предыдущего шага исследуется, а шест проверяется на равновесие. Это определяет, окончится ли посадка успешно либо неуспешно.
Давайте разработаем функцию, которая игнорирует текущее количество птиц на балансировочном шесте и просто заставляет Пьера поскользнуться и упасть. Мы назовём её >banana
:
>banana :: Pole –> Maybe Pole
>banana _ = Nothing
Мы можем поместить эту функцию в цепочку вместе с нашими приземлениями птиц. Она всегда будет вызывать падение канатоходца, поскольку игнорирует всё, что ей передаётся в качестве параметра, и неизменно возвращает неудачу.
>ghci> return (0, 0) >>= landLeft 1 >>= banana >>= landRight 1
>Nothing
Функции >banana
передаётся значение >Just (1, 0)
, но она всегда производит значение >Nothing
, которое заставляет всё выражение возвращать в результате >Nothing
. Какая досада!..
Вместо создания функций, которые игнорируют свои входные данные и просто возвращают предопределённое монадическое значение, мы можем использовать функцию >>>
. Вот её реализация по умолчанию:
>(>>) :: (Monad m) => m a –> m b –> m b
>m >> n = m >>= \_ –> n
Обычно передача какого-либо значения функции, которая игнорирует свой параметр и всегда возвращает некое предопределённое значение, всегда даёт в результате это предопределённое значение. При использовании монад, однако, нужно принимать во внимание их контекст и значение. Вот как функция >>>
действует при использовании с типом >Maybe
:
>ghci> Nothing >> Just 3
>Nothing
>ghci> Just 3 >> Just 4
>Just 4
>ghci> Just 3 >> Nothing
>Nothing
Если мы заменим оператор >> на вызов >>>= \_ –>
, легко увидеть, что происходит.
Мы можем заменить нашу функцию >banana
в цепочке на оператор >>>
и следующее за ним значение >Nothing
, чтобы получить гарантированную и очевидную неудачу:
>ghci> return (0, 0) >>= landLeft 1 >> Nothing >>= landRight 1