. Мы записали, что >g x y = f y x
. Если это верно, то верно и следующее: >f y x = g x y
. Держите это в уме – мы можем реализовать функцию ещё проще.
>flip' :: (a –> b –> c) –> b –> a –> c
>flip' f y x = f x y
Здесь мы воспользовались тем, что функции каррированы. Когда мы вызываем функцию >flip' f
без параметров >y
и >x
, то получаем функцию, которая принимает два параметра, но переставляет их при вызове. Даже несмотря на то, что такие «перевёрнутые» функции обычно передаются в другие функции, мы можем воспользоваться преимуществами каррирования при создании ФВП, если подумаем наперёд и запишем, каков будет конечный результат при вызове полностью определённых функций.
>ghci> zip [1,2,3,4,5,6] "привет"
>[(1,'п'),(2,'р'),(3,'и'),(4,'в'),(5,'е'),(6,'т')]
>ghci> flip' zip [1,2,3,4,5] "привет"
>[('п',1),('р',2),('и',3),('в',4),('е',5),('т',6)]
>ghci> zipWith div [2,2..] [10,8,6,4,2]
>[0,0,0,0,1]
>ghci> zipWith (flip' div) [2,2..] [10,8,6,4,2]
>[5,4,3,2,1]
Если применить функцию >flip'
к >zip
, то мы получим функцию, похожую на >zip
, за исключением того что элементы первого списка будут оказываться вторыми элементами пар результирующего списка, и наоборот. Функция >flip' div
делит свой второй параметр на первый, так что если мы передадим ей числа >2
и >10
, то результат будет такой же, что и в случае >div 10 2
.
Инструментарий функционального программиста
Как функциональные программисты мы редко будем обрабатывать одно значение. Обычно нам хочется сразу взять набор чисел, букв или значений каких-либо иных типов, а затем преобразовать всё это множество для получения результата. В данном разделе будет рассмотрен ряд полезных функций, которые позволяют нам работать с множествами значений.
Функция map
Функция >map
берёт функцию и список и применяет функцию к каждому элементу списка, формируя новый список. Давайте изучим сигнатуру этой функции и посмотрим, как она определена.
>map :: (a –> b) –> [a] –> [b]
>map _ [] = []
>map f (x:xs) = f x : map f xs
Сигнатура функции говорит нам, что функция >map
принимает на вход функцию, которая вычисляет значение типа >b
по параметру типа >a
, список элементов типа >a
и возвращает список элементов типа >b
. Интересно, что глядя на сигнатуру функции вы уже можете сказать, что она делает. Функция >map
– одна из самых универсальных ФВП, и она может использоваться миллионом разных способов. Рассмотрим её в действии:
>ghci> map (+3) [1,5,3,1,6]
>[4,8,6,4,9]
>ghci> map (++ "!") ["БУХ", "БАХ", "ПАФ"]
>["БУХ!","БАХ!","ПАФ!"]
>ghci> map (replicate 3) [3..6]
>[[3,3,3],[4,4,4],[5,5,5],[6,6,6]]
>ghci> map (map (^2)) [[1,2],[3,4,5,6],[7,8]]
>[[1,4],[9,16,25,36],[49,64]]
>ghci> map fst [(1,2),(3,5),(6,3),(2,6),(2,5)]
>[1,3,6,2,2]
Возможно, вы заметили, что нечто аналогичное можно сделать с помощью генератора списков. Вызов >map (+3) [1,5,3,1,6]
– это то же самое, что и >[x+3 | x <– [1,5,3,1,6]]
. Тем не менее использование функции >map
обеспечивает более читаемый код в случаях, когда вы просто применяете некоторую функцию к списку. Особенно когда применяются отображения к отображениям (>map
– к результатам выполнения функции