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

. Если помните, она принимает два параметра и возвращает максимальный из них. Если сделать вызов >max 4 5, то вначале будет создана функция, которая принимает один параметр и возвращает >4 или поданный на вход параметр – смотря что больше. Затем значение >5 передаётся в эту новую функцию, и мы получаем желаемый результат. В итоге оказывается, что следующие два вызова эквивалентны:

>ghci> max 4 5

>5

>ghci> (max 4) 5

>5

Чтобы понять, как это работает, давайте посмотрим на тип функции >max:

>ghci> :t max

>max :: (Ord a) => a –> a –> a

То же самое можно записать иначе:

>max :: (Ord a) => a –> (a –> a)

Прочитать запись можно так: функция >max принимает параметр типа >a и возвращает (>–>) функцию, которая принимает параметр типа >a и возвращает значение типа >a. Вот почему возвращаемый функцией тип и параметры функции просто разделяются стрелками.

Ну и чем это выгодно для нас? Проще говоря, если мы вызываем функцию и передаём ей не все параметры, то в результате получаем новую функцию, а именно – результат частичного применения исходной функции. Новая функция принимает столько параметров, сколько мы не использовали при вызове оригинальной функции. Частичное применение (или, если угодно, вызов функции не со всеми параметрами) – это изящный способ создания новых функций «на лету»: мы можем передать их другой функции или передать им ещё какие-нибудь параметры.



Посмотрим на эту простую функцию:

>multThree :: Int -> Int -> Int -> Int

>multThree x y z = x * y * z

Что происходит, если мы вызываем >multThree 3 5 9 или >((multThree 3) 5) 9? Сначала значение >3 применяется к >multThree, так как они разделены пробелом. Это создаёт функцию, которая принимает один параметр и возвращает новую функцию, умножающую на >3. Затем значение >5 применяется к новой функции, что даёт функцию, которая примет параметр и умножит его уже на >15. Значение >9 применяется к этой функции, и получается результат >135. Вы можете думать о функциях как о маленьких фабриках, которые берут какие-то материалы и что-то производят. Пользуясь такой аналогией, мы даём фабрике >multThree число >3, и, вместо того чтобы выдать число, она возвращает нам фабрику немного поменьше. Эта новая фабрика получает число >5 и тоже выдаёт фабрику. Третья фабрика при получении числа >9 производит, наконец, результат — число >135. Вспомним, что тип этой функции может быть записан так:

>multThree :: Int -> (Int -> (Int -> Int))

Перед символом >–> пишется тип параметра функции; после записывается тип значения, которое функция вернёт. Таким образом, наша функция принимает параметр типа