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

>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)

Может показаться, что всё хорошо, но если вы проследите за шагами, то увидите, что на правой стороне одновременно находятся четыре птицы – а на левой ни одной! Чтобы исправить это, мы должны ещё раз взглянуть на наши функции