Подтвердить что ты не робот

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

Я читаю этот учебник по Haskell. Они определяют состав функций следующим образом:

(.)                     :: (b->c) -> (a->b) -> (a->c)
f . g                   = \ x -> f (g x)

Никаких примеров не было предоставлено, что, я думаю, просветит меня относительно того, что здесь определено.

Может ли кто-нибудь представить простой пример (с объяснением) того, как используется композиция функции?

4b9b3361

Ответ 1

Состав функций - это способ "скомпоновать" две функции вместе в одну функцию. Вот пример:

Скажите, что у вас есть следующие функции:

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]

Немного короче, меньше места для ошибок.

Ответ 2

Замечательная сторона. Состав функции является эквивалентом силлогизма в логике:

Все люди смертны. Сократ - это человек. Поэтому Сократ смертен.

Силлогизм составляет два существенных значения в одном:

(Man => Mortal), (Socrates => Man), therefore (Socrates => Mortal)

Поэтому...

(B => C) => (A => B) => (A => C)

... который является типом функции ..

Ответ 3

состав 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)); }

Ответ 4

Этот пример надуман, но предположим, что

sqr x = x * x  
inc x = x + 1

и мы хотим написать функцию, вычисляющую x ^ 2 + 1. Мы можем написать

xSquaredPlusOne = inc . sqr

(что означает

xSquaredPlusOne x = (inc . sqr) x

что означает

xSquaredPlusOne x = inc(sqr x)

так как f = inc и g = sqr).

Ответ 5

Из страница HaskellWiki о составе функции:

desort = (reverse . sort)

Теперь desort - это функция, сортирующая список в обратном порядке. В принципе, desort передает свои аргументы в sort, а затем возвращает возвращаемое значение из sort в reverse, возвращает это. Поэтому он сортирует его, а затем меняет отсортированный список.

Ответ 6

Состав функций - способ объединения двух или более функций вместе. Он часто сравнивается с оболочкой. Например, в оболочке в стиле Unix вы можете написать что-то вроде

cat foo.txt | sort -n | less

Это запускает cat, передает свой вывод на sort и подает вывод с этого на less.

Строго, это похоже на оператор Haskell $. Вы можете написать что-то вроде

sum $ sort $ filter (> 0) $ my_list

Обратите внимание, что в отличие от примера оболочки это читается справа налево. Итак, мы начинаем с my_list в качестве входных данных, затем выполняем над ним filter, тогда мы sort it, а затем вычисляем его sum.

Оператор композиции функции . делает нечто подобное. В приведенном выше примере выдается число; в приведенном ниже примере создается функция:

sum . sort . filter (> 0)

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

my_function = sum . sort . filter (> 0)

Или вы можете передать его как аргумент другой функции:

map (sum . sort . filter (> 0)) my_lists

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