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

принимает два параметра, хоть мы и знаем, что происходит «за кулисами».

Тело функции >applyTwice достаточно простое. Мы используем параметр >f как функцию, применяя её к параметру >x (для этого разделяем их пробелом), после чего передаём результат снова в функцию >f. Давайте поэкспериментируем с функцией:

>ghci> applyTwice (+3) 10

>16

>ghci> applyTwice (++ " ХА-ХА") "ЭЙ"

>"ЭЙ ХА-ХА ХА-ХА"

>ghci> applyTwice ("ХА-ХА " ++) "ЭЙ"

>"ХА-ХА ХА-ХА ЭЙ"

>ghci> applyTwice (multThree 2 2) 9

>144

>ghci> applyTwice (3:) [1]

>[3,3,1]

Красота и полезность частичного применения очевидны. Если наша функция требует передать ей функцию одного аргумента, мы можем частично применить функцию-параметр таким образом, чтобы оставался неопределённым всего один параметр, и затем передать её нашей функции. Например, функция >+ принимает два параметра; с помощью сечений мы можем частично применить её так, чтобы остался только один.

Реализация функции zipWith

Теперь попробуем применить ФВП для реализации очень полезной функции из стандартной библиотеки. Она называется >zipWith. Эта функция принимает функцию и два списка, а затем соединяет списки, применяя переданную функцию для соответствующих элементов. Вот как мы её реализуем:

>zipWith' :: (a –> b –> c) –> [a] –> [b] –> [c]

>zipWith' _ [] _ = []

>zipWith' _ _ [] = []

>zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys

Посмотрите на объявление типа. Первый параметр – это функция, которая принимает два значения и возвращает одно. Параметры этой функции не обязательно должны быть одинакового типа, но могут. Второй и третий параметры – списки. Результат тоже является списком. Первым идёт список элементов типа >a, потому что функция сцепления принимает значение типа >a в качестве первого параметра. Второй должен быть списком из элементов типа >b, потому что второй параметр у связывающей функции имеет тип >b. Результат – список элементов типа >c. Если объявление функции говорит, что она принимает функцию типа >a –> b –> c как параметр, это означает, что она также примет и функцию >a –> a –> a, но не наоборот.

ПРИМЕЧАНИЕ. Запомните: когда вы создаёте функции, особенно высших порядков, и не уверены, каким должен быть тип, вы можете попробовать опустить объявление типа, а затем проверить, какой тип выведет язык Haskell, используя команду >:t в GHCi.

Устройство данной функции очень похоже на обычную функцию >zip. Базовые случаи одинаковы. Единственный дополнительный аргумент – соединяющая функция, но он не влияет на базовые случаи; мы просто используем для него маску подстановки >_. Тело функции в последнем образце также очень похоже на функцию