52700.fb2
Теперь посмотрим на полное определение функции применения:
infixr 0 $
($) :: (a -> b) -> a -> b
f $ x
=
f x
Ответ на вопрос о полезности этой функции кроется в её приоритете. Ей назначен самый низкий прио-
ритет. Она будет исполняться в последнюю очередь. Очень часто возникают ситуации вроде:
Приоритет инфиксных операций | 77
foldNat zero succ (Succ b) = succ (foldNat zero succ b)
С помощью функции применения мы можем переписать это определение так:
foldNat zero succ (Succ b) = succ $ foldNat zero succ b
Если бы мы написали без скобок:
... = succ foldNat zero succ b
То выражение было бы сгруппировано так:
... = (((succ foldNat) zero) succ) b
Но поскольку мы поставили барьер в виде операции ($) с низким приоритетом, группировка скобок
произойдёт так:
... = (succ $ ((foldNat zero) succ) b)
Это как раз то, что нам нужно. Преимущество этого подхода проявляется особенно ярко если у нас
несколько вложенных функций на конце выражения:
xs :: [Int]
xs = reverse $ map ((+1) . (*10)) $ filter even $ ns 40
ns :: Int -> [Int]
ns 0
= []
ns n
= n : ns (n - 1)
В списке xs мы сначала создаём в функции ns убывающий список чисел, затем оставляем лишь чётные,
потом применяем два арифметических действия ко всем элементам списка, затем переворачиваем список.
Проверим работает ли это в интерпретаторе, заодно поупражняемся в композиционном стиле:
Prelude> let ns n = if (n == 0) then [] else n : ns (n - 1)
Prelude> let even x = 0 == mod x 2
Prelude> let xs = reverse $ map ((+1) . (*10)) $ filter even $ ns 20
Prelude> xs
[21,41,61,81,101,121,141,161,181,201]
Если бы не функция применения нам пришлось бы написать это выражение так:
xs = reverse (map ((+1) . (*10)) (filter even (ns 40)))
5.3 Функциональный калькулятор
Мне бы хотелось сделать акцент на одном из вступительных предложений этой главы:
За счёт развитых средств составления новых функций в Haskell пользователь определяет лишь
базовые функции, получая остальные “на лету” применением двух-трёх операций, это выглядит
примерно как (2+3)*5, где вместо чисел стоят базовые функции, а операции + и * составляют
новые функции из простейших.
Такие обобщённые функции как id, const, (. ), map filter позволяют очень легко комбинировать различ-
ные функции. Бесточечный стиль записи функций превращает функции в простые значения или значения-
константы, которые можно подставлять в другие функции. В этом разделе мы немного потренируемся в пе-
регрузке численных значений и превратим числа в функции, функции и в самом деле станут константами.
Мы определим экземпляр Num для функций, которые возвращают числа. Смысл этих операций заключается в