Состав функции Хаскеля
Я читаю этот урок на Haskell. Они определяют состав функции следующим образом:
(.) :: (b->c) -> (a->b) -> (a->c)
f . g = \ x -> f (g x)
Не было предоставлено никаких примеров, которые, я полагаю, просветили бы меня относительно того, что здесь определено.
Может ли кто-нибудь привести простой пример (с объяснением) того, как используется композиция функций?
6 ответов
Композиция функций - это способ "объединить" две функции в одну функцию. Вот пример:
Скажем, у вас есть эти функции:
even :: Int -> Bool
not :: Bool -> Bool
и вы хотите определить свой собственный myOdd :: Int -> Bool
Функция с использованием двух выше.
Очевидный способ сделать это заключается в следующем:
myOdd :: Int -> Bool
myOdd x = not (even x)
Но это можно сделать более кратко, используя композицию функций:
myOdd :: Int -> Bool
myOdd = not . even
myOdd
функции ведут себя точно так же, но вторая создается путем "склеивания" двух функций вместе.
Сценарий, в котором это особенно полезно, состоит в том, чтобы устранить необходимость в явной лямбде. Например:
map (\x -> not (even x)) [1..9]
можно переписать на:
map (not . even) [1..9]
Немного короче, меньше места для ошибок.
Веселое примечание. Композиция функций является эквивалентом силлогизма в логике:
Все люди смертны. Сократ это человек. Поэтому Сократ смертен.
Силлогизм объединяет два материальных значения в одно:
(Man => Mortal), (Socrates => Man), therefore (Socrates => Mortal)
Следовательно...
(b -> c) -> (a -> b) -> (a -> c)
... который является типом .
функция.
Состав f
а также g
это функция, которая сначала применяется g
к его аргументу, то f
на значение, возвращаемое g
, Затем он возвращает возвращаемое значение f
,
Эта личность может быть поучительной:
f (g x) = (f . g) x
Если у вас есть фон Java/C, рассмотрите этот пример:
int f(int x);
int g(int x);
int theComposition(int x) { return f(g(x)); }
Этот пример надуманный, но предположим, что мы имеем
sqr x = x * x
inc x = x + 1
и мы хотим написать функцию, которая вычисляет х ^2+1. Мы можем написать
xSquaredPlusOne = inc . sqr
(что значит
xSquaredPlusOne x = (inc . sqr) x
что значит
xSquaredPlusOne x = inc(sqr x)
так как f=inc и g=sqr).
Со страницы HaskellWiki по составу функций:
desort = (reverse . sort)
Сейчас desort
это функция, которая сортирует список в обратном порядке В принципе, desort
кормит свои аргументы в sort
, а затем передает возвращаемое значение из sort
в reverse
, возвращает это. Таким образом, он сортирует его, а затем переворачивает отсортированный список.
Композиция функций - это способ связать две или более функции вместе. Его часто сравнивают с трубами оболочки. Например, в оболочке в стиле Unix вы можете написать что-то вроде
cat foo.txt | sort -n | less
Это работает cat
, передает свой вывод sort
и передает вывод от этого к less
,
Строго говоря, это как Хаскель $
оператор. Вы могли бы написать что-то вроде
sum $ sort $ filter (> 0) $ my_list
Обратите внимание, что, в отличие от примера оболочки, это читается справа налево. Итак, начнем с my_list
в качестве ввода, то мы бежим filter
над этим, то мы sort
это, а затем мы рассчитываем sum
этого
Оператор композиции функций, .
Делает что-то подобное. В приведенном выше примере получается число; Пример ниже производит функцию:
sum . sort . filter (> 0)
Обратите внимание, что мы на самом деле не вводили список в это. Вместо этого мы только что создали новую функцию и можем добавить к ней несколько разных списков. Например, вы можете назвать эту функцию:
my_function = sum . sort . filter (> 0)
Или вы можете передать его в качестве аргумента другой функции:
map (sum . sort . filter (> 0)) my_lists
Вы можете использовать его в любом месте, где вы можете использовать любую другую функцию. Это просто быстрый и понятный способ сказать: "Я хочу связать эти функции вместе".