Haskell:翻转功能的目的是什么?

时间:2018-07-01 06:22:00

标签: haskell arguments flip

令我感到惊讶的是,以前没有问过这个问题。也许这是一个愚蠢的问题。

我知道翻页会改变两个参数的顺序。

示例:

(-) 5 3
= 5 - 3
= 2

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

但是为什么我需要这样的功能?为什么不只是手动更改输入?

为什么不只写:

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

3 个答案:

答案 0 :(得分:12)

一个函数不太可能在立即应用于两个或多个参数的函数上使用flip函数,但是flip在两种情况下很有用:

  1. 如果将函数高阶传递给另一个函数,则不能简单地在调用站点上反转参数,因为调用站点在另一个函数中!例如,这两个表达式产生非常不同的结果:

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

    在这种情况下,因为我们不直接应用(-),所以我们不能交换(-)的参数。 foldl适用于我们。因此,我们可以使用flip (-)而不是写出整个lambda \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]]
    

    有时候,人们不会使用in flip,而是使用infix语法,因为operator sections具有唯一的属性,可以提供第一个函数的第二个参数。因此,写(`f` x)等同于写flip f x。就我个人而言,我认为直接写flip通常更容易阅读,但这是一个品味问题。

答案 1 :(得分:4)

有时候,您可能想通过提供第二个参数来使用函数,而从其他地方获取它的第一个参数。例如:

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

尽管这也可以写成:

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

另一个用例是当第二个参数很长时:

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

但是您始终可以使用let表达式来命名第一个参数计算,然后不使用flip

答案 2 :(得分:4)

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]