Состав функции .
- это не то же самое, что приложение функции $
. Вы не можете поменять $
на .
и ожидать, что программа будет иметь то же значение. Это разные вещи.
Во-первых, функция приложения . Он определяется следующим образом:
f $ x = f x
Оператор принимает функцию с левой стороны и значение с правой стороны и просто передает значение функции в качестве аргумента. Возьмем, к примеру, ваше выражение:
last $ filter (filterNearest x) possibilities
Сравните с определением оператора $
: в вашем коде f
равно last
, а x
равно filter (filterNearest x) possibilities
. Следовательно, ваш код эквивалентен этому:
last (filter (filterNearest x) possibilities)
Теперь давайте посмотрим на композицию функций . Он определяется следующим образом:
f . g = \y -> f (g y)
Это означает, что результатом объединения двух функций f
и g
будет другая функция , которая передает свой аргумент g
и затем передает возвращаемое значение g
в f
.
Теперь взгляните на ваш предпринятый код:
last . filter (filterNearest x) possibilities
Сравните с определением: f
is last
и g
равно filter (filterNearest x) possibilities
. Важно отметить, что второй аргумент filter (filterNearest x) possibilities
- это , а не функция ! Поэтому неудивительно, что его нельзя составить с помощью композиции функций.
Но ваша интуиция на самом деле верна (или это ваше домашнее задание?): Композиция функций действительно может использоваться в этом контексте и приносить некоторую пользу.
Давайте посмотрим на это выражение:
last . filter (filterNearest x)
Сравните с определением: f
равно last
и g
равно filter (filterNearest x)
. Теперь оба аргумента фактически являются функциями, и, следовательно, можно применять композицию функций. Чтобы увидеть результат его применения, просто используйте подстановку:
last . filter (filterNearest x)
== \y -> last (filter (filterNearest x) y)
Таким образом, результатом такой композиции является функция, которая принимает список в качестве параметра, фильтрует этот список, а затем принимает последний элемент результат. Таким образом, полное определение findNearest
может выглядеть так:
findNearest :: Int -> [Int] -> Int
findNearest x = last . filter (filterNearest x)
Видите, что спасло вас от композиции функций? Теперь вам не нужно выписывать второй параметр! Большинство Haskell программистов сочли бы это преимуществом, но я также знаю некоторых людей, которые не одобряют это, утверждая, что это делает программу менее понятной. Каждому свое, но полезно отметить это несогласие.
Я оставлю подобное преобразование sortData
в качестве упражнения.