и
>landRight.
Необходимо дать функциям >landLeft и >landRight возможность завершаться неуспешно. Нам нужно, чтобы они возвращали новый шест, если равновесие поддерживается, но завершались неуспешно, если птицы приземляются неравномерно. И какой способ лучше подойдёт для добавления к значению контекста неудачи, чем использование типа >Maybe? Давайте переработаем эти функции:
>landLeft :: Birds –> Pole –> Maybe Pole
>landLeft n (left,right)
> | abs ((left + n) - right) < 4 = Just (left + n, right)
> | otherwise = Nothing
>landRight :: Birds –> Pole –> Maybe Pole
>landRight n (left,right)
> | abs (left - (right + n)) < 4 = Just (left, right + n)
> | otherwise = Nothing
Вместо того чтобы вернуть значение типа >Pole, эти функции теперь возвращают значения типа >Maybe Pole. Они по-прежнему принимают количество птиц и прежний шест, как и ранее, но затем проверяют, выведет ли Пьера из равновесия приземление такого количества птиц. Мы используем охранные выражения, чтобы проверить, меньше ли разница в количестве птиц на новом шесте, чем 4. Если меньше, оборачиваем новый шест в конструктор >Just и возвращаем это. Если не меньше, возвращаем значение >Nothing, сигнализируя о неудаче.
Давайте опробуем этих деток:
>ghci> landLeft 2 (0, 0)
>Just (2,0)
>ghci> landLeft 10 (0, 3)
>Nothing
Когда мы приземляем птиц, не выводя Пьера из равновесия, мы получаем новый шест, обёрнутый в конструктор >Just. Но когда значительное количество птиц в итоге оказывается на одной стороне шеста, в результате мы получаем значение >Nothing. Всё это здорово, но, похоже, мы потеряли возможность многократного приземления птиц на шесте! Выполнить >landLeft 1 (landRight 1 (0, 0)) больше нельзя, потому что когда >landRight 1 применяется к >(0, 0), мы получаем значение не типа >Pole, а типа >Maybe Pole. Функция >landLeft 1 принимает параметр типа >Pole, а не >Maybe Pole.
Нам нужен способ получения >Maybe Pole и передачи его функции, которая принимает >Pole и возвращает >Maybe Pole. К счастью, у нас есть операция >>>=, которая делает именно это для типа >Maybe. Давайте попробуем:
>ghci> landRight 1 (0, 0) >>= landLeft 2
>Just (2,1)
Вспомните, что функция >landLeft 2 имеет тип >Pole –> Maybe Pole. Мы не можем просто передать ей значение типа >Maybe Pole, которое является результатом вызова функции >landRight 1 (0, 0), поэтому используем операцию >>>=, чтобы взять это значение с контекстом и отдать его функции >landLeft 2. Операция >>>= действительно позволяет нам обрабатывать значения типа >Maybe как значения с контекстом. Если мы передадим значение