>type Birds = Int
>type Pole = (Birds, Birds)
Сначала мы создали синоним типа для >Int
, названный >Birds
, потому что мы используем целые числа для представления количества имеющихся птиц. Затем создали синоним типа (>Birds
, >Birds
) и назвали его >Pole
(учтите: это означает «шест» – ничего общего ни с поляками, ни с человеком по имени Поль).
А теперь как насчёт того, чтобы добавить функции, которые принимают количество птиц и производят их приземление на одной стороне шеста или на другой?
>landLeft :: Birds –> Pole –> Pole
>landLeft n (left, right) = (left + n, right)
>landRight :: Birds –> Pole –> Pole
>landRight n (left, right) = (left, right + n)
Давайте проверим их:
>ghci> landLeft 2 (0, 0)
>(2,0)
>ghci> landRight 1 (1, 2)
>(1,3)
>ghci> landRight (-1) (1,2)
>(1,1)
Чтобы заставить птиц улететь, мы просто произвели приземление отрицательного количества птиц на одной стороне. Поскольку приземление птицы на >Pole
возвращает >Pole
, мы можем сцепить применения функций >landLeft
и >landRight
:
>ghci> landLeft 2 (landRight 1 (landLeft 1 (0, 0)))
>(3,1)
Когда мы применяем функцию >landLeft 1
к значению >(0, 0)
, у нас получается результат >(1, 0)
. Затем мы усаживаем птицу на правой стороне, что даёт в результате >(1, 1)
. Наконец, две птицы приземляются на левой стороне, что даёт в результате >(3, 1)
. Мы применяем функцию к чему-либо, сначала записывая функцию, а затем её параметр, но здесь было бы лучше, если бы первым шел шест, а потом функция посадки. Предположим, мы создали вот такую функцию:
>x -: f = f x
Можно применять функции, сначала записывая параметр, а затем функцию:
>ghci> 100 -: (*3)
>300
>ghci> True -: not
>False
>ghci> (0, 0) -: landLeft 2
>(2,0)
Используя эту форму, мы можем многократно производить приземление птиц на шест в более «читабельном» виде:
>ghci> (0, 0) -: landLeft 1 -: landRight 1 -: landLeft 2
>(3,1)
Круто!.. Эта версия эквивалентна предыдущей, где мы многократно усаживали птиц на шест, но выглядит она яснее. Здесь очевиднее, что мы начинаем с >(0, 0)
, а затем усаживаем одну птицу слева, потом одну – справа, и в довершение две – слева.
Пока всё идёт нормально, но что произойдёт, если десять птиц приземлятся на одной стороне?
>ghci> landLeft 10 (0, 3)
>(10,3)
Десять птиц с левой стороны и лишь три с правой?! Этого достаточно, чтобы отправить в полёт самого Пьера!.. Довольно очевидная вещь. Но что если бы у нас была примерно такая последовательность посадок:
>ghci> (0, 0) -: landLeft 1 -: landRight 4 -: landLeft (-1) -: landRight (-2)
>(0,2)
Может показаться, что всё хорошо, но если вы проследите за шагами, то увидите, что на правой стороне одновременно находятся четыре птицы – а на левой ни одной! Чтобы исправить это, мы должны ещё раз взглянуть на наши функции