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

, поскольку нам не к чему применить эту функцию.

Мы не смогли бы достигнуть этого, просто используя >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