Haskell: цель функции переворота? - PullRequest
0 голосов
/ 01 июля 2018

Я немного удивлен, что об этом раньше не спрашивали. Может быть, это глупый вопрос.

Я знаю, что flip меняет порядок двух аргументов.

Пример:

(-) 5 3
= 5 - 3
= 2

flip (-) 5 3
= 3 - 5
= -2

Но зачем мне такая функция? Почему бы просто не изменить входы вручную?

Почему бы просто не написать:

(-) 3 5
= 3 - 5
= -2

Ответы [ 3 ]

0 голосов
/ 01 июля 2018

Иногда вам может понадобиться использовать функцию, указав второй параметр, но взять его первый параметр откуда-то еще. Например:

map (flip (-) 5) [1..5]

Хотя это также можно записать как:

map (\x -> x - 5) [1..5]

Еще один вариант использования, когда второй аргумент длинный:

flip (-) 5 $
   if odd x
      then x + 1
      else x

Но вы всегда можете использовать выражение let, чтобы назвать первое вычисление параметра, а затем не использовать flip.

0 голосов
/ 01 июля 2018

Один очень полезный пример использования 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]
0 голосов
/ 01 июля 2018

Маловероятно, что когда-либо будет использоваться функция flip для функции, которая немедленно применяется к двум или более аргументам, но flip может быть полезен в двух ситуациях:

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

    ghci> foldl (-) 0 [1, 2, 3, 4]
    -10
    ghci> foldl (flip (-)) 0 [1, 2, 3, 4]
    2
    

    В этом случае мы не можем поменять местами аргументы (-), потому что мы не применяем (-) напрямую; foldl применяет это для нас. Таким образом, мы можем использовать flip (-) вместо записи всей лямбды \x y -> y - x.

  2. Кроме того, может быть полезно использовать 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 напрямую легче читать, но это дело вкуса.

...