и
>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
как значения с контекстом. Если мы передадим значение