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

>[–14,–15,–27]

в

>ghci> map (negate . sum . tail) [[1..5],[3..6],[1..7]]

>[–14,–15,–27]

Функция >negate . sum . tail принимает список, применяет к нему функцию >tail, суммирует результат и умножает полученное число на >-1. Получаем точный эквивалент анонимной функции из предыдущего примера.

Композиция функций с несколькими параметрами

Ну а как насчёт функций, которые принимают несколько параметров? Если мы хотим использовать их в композиции, обычно мы частично применяем их до тех пор, пока не получим функцию, принимающую только один параметр. Запись

>sum (replicate 5 (max 6.7 8.9))

может быть преобразована так:

>(sum . replicate 5) (max 6.7 8.9)

или так:

>sum . replicate 5 $ max 6.7 8.9

Функция >replicate 5 применяется к результату вычисления >max 6.7 8.9, после чего элементы полученного списка суммируются. Обратите внимание, что функция >replicate частично применена так, чтобы у неё остался только один параметр, так что теперь результат >max 6.7 8.9 передаётся на вход >replicate 5; новым результатом оказывается список чисел, который потом передаётся функции >sum.

Если вы хотите переписать выражение с кучей скобок, используя функциональную композицию, можно сначала записать самую внутреннюю функцию с её параметрами, затем поставить перед ней знак >$, а после этого пристраивать вызовы всех других функций, записывая их без последнего параметра и разделяя точками. Например, выражение

>replicate 2 (product (map (*3) (zipWith max [1,2] [4,5])))

можно переписать так:

>replicate 2 . product . map (*3) $ zipWith max [1,2] [4,5]

Как из одного выражения получилось другое? Ну, во-первых, мы посмотрели на самую правую функцию и её параметры как раз перед группой закрывающихся скобок. Это функция >zipWith max [1,2] [4,5]. Так её и запишем:

>zipWith max [1,2] [4,5]

Затем смотрим на функцию, которая применяется к >zipWith max [1,2] [4,5], это >map (*3). Поэтому мы ставим между ней и тем, что было раньше, знак >$:

>map (*3) $ zipWith max [1,2] [4,5]

Теперь начинаются композиции. Проверяем, какая функция применяется ко всему этому, и присоединяем её к >map (*3):

>product . map (*3) $ zipWith max [1,2] [4,5]

Наконец, дописываем функцию >replicate 2 и получаем окончательное выражение:

>replicate 2 . product . map (*3) $ zipWith max [1,2] [4,5]

Если выражение заканчивалось на три закрывающие скобки, велики шансы, что у вас получится два оператора композиции.

Бесточечная нотация

Композиция функций часто используется и для так называемого бесточечного стиля записи функций. Возьмём, для примера, функцию, которую мы написали ранее:

>sum' :: (Num a) => [a] –> a