52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 76

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 76

foldNat zero succ Zero

= zero

foldNat zero succ (Succ b) = succ (foldNat zero succ b)

То мы можем переписать с помощью функции композиции эту функцию так:

add :: Nat -> Nat -> Nat

add = foldNat

id

(Succ . )

Куда делись аргументы? Они выражаются через функции id и (. ). Поведение этой функции лучше про-

иллюстрировать на примере. Пусть у нас есть два числа типа Nat:

two

= Succ (Succ Zero)

three

= Succ (Succ (Succ Zero))

Вычислим

add two three

Вспомним о частичном применении:

Обобщённые функции | 73

add two three

=>

(add two) three

=>

(foldNat id (Succ . ) (Succ (Succ Zero))) three

Теперь функция свёртки заменит все конструкторы Succ на (Succ . ), а конструкторы Zero на id:

=>

((Succ . ) ((Succ . ) id)) three

Что это за монстр?

((Succ . ) ((Succ . ) id))

Функция (Succ . ) это левое сечение операции (. ). Эта функция, которая принимает функции и возвра-

щает функции. Она принимает функцию и навешивает на её выход конструктор Succ. Давайте упростим это

большое выражение с помощью определений функций (. ) и id:

((Succ . ) ((Succ . ) id))

=>

(Succ . ) (\x -> Succ (id x))

=>

(Succ . ) (\x -> Succ x)

=>

\x -> Succ (Succ x)

Теперь нам осталось применить к этой функции наше второе значение:

(\x -> Succ (Succ x)) three

=>

Succ (Succ three)

=>

Succ (Succ (Succ (Succ (Succ x))))

Так мы получили, что и ожидалось от сложения. За каждый конструктор Succ в первом аргументе мы

добавляем применение Succ к результату, а вместо Zero протаскиваем через id второй аргумент.

Аналогия с числами

С помощью функции композиции мы можем нанизывать друг на друга списки функций. Попробуем в

интерпретаторе:

Prelude> let f = foldr (. ) id [sin, cos, sin, cos, exp, (+1), tan]