Состав функции Хаскеля

Я читаю этот урок на 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

Вы можете использовать его в любом месте, где вы можете использовать любую другую функцию. Это просто быстрый и понятный способ сказать: "Я хочу связать эти функции вместе".

Другие вопросы по тегам