Я немного удивлен, что об этом не спросили раньше. Может это глупый вопрос.
Я знаю, что флип меняет порядок двух аргументов.
Пример:
(-) 5 3
= 5 - 3
= 2
flip (-) 5 3
= 3 - 5
= -2
Но зачем мне такая функция? Почему бы просто не изменить ввод вручную?
Почему бы просто не написать:
(-) 3 5
= 3 - 5
= -2





Маловероятно, что когда-либо будет использоваться функция flip для функции, которая сразу применяется к двум или более аргументам, но flip может быть полезен в двух ситуациях:
Если функция передается более высокого порядка другой функции, нельзя просто изменить аргументы в месте вызова, поскольку сайт вызова находится в другой функции! Например, эти два выражения дают очень разные результаты:
ghci> foldl (-) 0 [1, 2, 3, 4]
-10
ghci> foldl (flip (-)) 0 [1, 2, 3, 4]
2
В этом случае мы не можем поменять местами аргументы (-), потому что мы не применяем (-) напрямую; foldl применяет это для нас. Таким образом, мы можем использовать flip (-) вместо записи всей лямбда-выражения \x y -> y - x.
Кроме того, может быть полезно использовать flip для частичного применения функции ко второму аргументу. Например, мы могли бы использовать flip для написания функции, которая строит бесконечный список, используя функцию построителя, которой предоставляется индекс элемента в списке:
buildList :: (Integer -> a) -> [a]
buildList = flip map [0..]
ghci> take 10 (buildList (\x -> x * x))
[0,1,4,9,16,25,36,49,64,81]
Возможно, чаще это используется, когда мы хотим частично применить второй аргумент функции, которая будет использоваться более высокого порядка, как в первом примере:
ghci> map (flip map [1, 2, 3]) [(+ 1), (* 2)]
[[2,3,4],[2,4,6]]
Иногда вместо использования flip в таком случае люди будут использовать инфиксный синтаксис, поскольку операторские секции имеет уникальное свойство, которое они могут предоставить первым вторым аргументом или же функции. Следовательно, запись (`f` x) эквивалентна записи flip f x. Лично я считаю, что писать flip напрямую обычно легче, но это дело вкуса.
@simplesystems Да, вы всегда можете написать то же самое без flip, просто вставив определение flip на сайте его использования. Но использование flip позволяет писать в безточечный стиль, который некоторые люди считают более читаемым, а некоторые - нет. Лично я считаю, что это ситуационный характер - я думаю, что иногда бесточечный стиль устраняет шум и упрощает понимание, - но в этом случае, я согласен, версия с явным аргументом действительно не хуже.
Другими словами, вы всегда можете заменить flip f на \x y -> f y x, так что flip ни в коем случае не обязателен! Но, как и все функции, это абстракция, хоть и небольшая.
@simplesystems Возможно, вас заинтересует stackoverflow.com/q/7402528/176841. Есть некоторая теория, которую вы можете изучить здесь, если хотите: в haskell flip позволяет нам избегать использования лямбда-выражений (для ясности, эстетики); Интересно, что лямбды никогда не являются нужно: можно выбрать несколько функций («комбинаторов», таких как flip), так что у вас есть такая мощная система, как лямбда-исчисление. Это называется основа, наиболее известным из которых является комбинаторное исчисление SKI.
flip обычно называется C и также может составлять часть основы: en.wikipedia.org/wiki/B,_C,_K,_W_system. Я пытаюсь понять, что flip (и const, и id) не произвольный, но на самом деле вы обнаружите это в теории, если вы думаете о том, как вы могли бы выразить вычисления, не прибегая к лямбдам (что часто является целью в haskell для ясности / эстетических соображений, как описано в других ответах здесь)
Иногда вы захотите использовать функцию, указав второй параметр, но взяв первый параметр откуда-то еще. Например:
map (flip (-) 5) [1..5]
Хотя это также можно записать как:
map (\x -> x - 5) [1..5]
Другой вариант использования - когда второй аргумент длинный:
flip (-) 5 $
if odd x
then x + 1
else x
Но вы всегда можете использовать выражение let, чтобы назвать первое вычисление параметра, а затем не использовать flip.
что означает знак $ в третьем примере?
+1, особенно мне нравится твой последний пример. Я определенно видел это время от времени (и, возможно, я даже написал это сам один или два раза), и я не думал включать это в свой ответ. :)
simplesystems, я использую его вместо скобок. Подробнее об этом можно прочитать здесь: haskell-lang.org/tutorial/operators
Алексис, да, я обнаружил, что этот вариант использования мне больше подходит! (Во многих случаях я также предпочитаю использовать обратные кавычки вместо переворота).
Один очень полезный пример использования flip - сортировка по убыванию. Вы можете увидеть, как это работает в ghci:
ghci> import Data.List
ghci> :t sortBy
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
ghci> :t compare
compare :: Ord a => a -> a -> Ordering
ghci> sortBy compare [2,1,3]
[1,2,3]
ghci> sortBy (flip compare) [2,1,3]
[3,2,1]
В вашем примере buildList вы просто указываете функцию buildList, например buildList f = map f [0 ..]