【问题标题】:Haskell: applying flip twice (type of flip flip)Haskell:两次应用翻转(翻转类型)
【发布时间】:2019-01-29 20:15:58
【问题描述】:

我正在学习 Haskell 的一些基本功能。我正在用 Flip 做一些练习,它接受两个参数的函数并评估结果,翻转参数的顺序。考虑函数 flip flip,我会认为,按照翻转的定义,它翻转参数两次,以原始顺序使用参数评估原始函数。当我用 ghci 检查函数类型来检查这个假设时,它产生了:

翻转翻转 :: b -> (a -> b -> c) -> a -> c

我不明白为什么这是翻转翻转的函数类型。它接受参数 b 和参数 (a -> b -> c) 并产生一个函数 a -> c。为什么会这样?我真的很感激一个解释,因为我对此感到迷茫。提前致谢

【问题讨论】:

  • 你不翻转两次,你翻转flip函数。
  • 为了好玩,试试flip flip flip

标签: function haskell functional-programming


【解决方案1】:

翻转两次将是\f -> flip (flip f),或flip . flip。这确实具有(a -> b -> c) -> (a -> b -> c) 类型。

您在这里所做的是在flip 函数上应用flip,即翻转flip 的参数顺序。所以如果我们从

flip :: (a -> b -> c) -> b -> a -> c
-- and, as the type of the argument
flip :: (a' -> b' -> c') -> b' -> a' -> c'

如果我们匹配类型

a = (a' -> b' -> c')
b = b'
c = a' -> c'

我们得到结果

flip flip :: b' -> (a' -> b' -> c') -> (a' -> c')

【讨论】:

  • 感谢您的简洁回答。我意识到我还没有完全明白一件事(对不起,如果这个问题听起来很微不足道,但我对 Haskell 完全陌生)。为什么你匹配“b = b'”而不是“b = (b'->a')”,然后是“c = c'”?为什么我给的第一个关联是有效的而不是另一个?
  • 因为-> 语法的右结合性。明确说明,类型是((a -> (b -> (c))) -> (b -> (a -> (c))))。 Haskell 中的所有函数实际上都是一元的(只接受一个参数),它们只是可能返回另一个函数,该函数再次接受另一个参数。 (b' -> (a' -> c')) 类型与 ((b' -> a') -> c') 不同,它们只是不匹配。
【解决方案2】:

让我们看看类型:

flip :: (a -> b -> c) -> b -> (a -> c)
flip :: (d            -> e ->  f     ) -> e ->  d            ->  f
flip flip ::                              b -> (a -> b -> c) -> (a -> c)

换句话说,flip 反转其参数的前两个参数,flip 的前两个参数是要翻转的函数和该函数的第二个参数。因此,当您翻转它时,顺序变为“第二个参数”、“函数”、“第一个参数”,而不是按“函数”、“第二个参数”、“第一个参数”的顺序获取参数。

如果你想翻转,然后再翻转回来,你可以这样做:

doubleflip x = flip (flip x)

或等效:

doubleflip = flip . flip

(.) 运算符将右侧的输出馈送到左侧。

【讨论】:

    【解决方案3】:

    您确实应用flip 函数两次。如果您想申请flip两次,您正在寻找:

    <b>flip . flip</b> :: (b -&gt; a -&gt; c) -&gt; b -&gt; a -&gt; c

    您在这里所做的是翻转 flip 函数。所以它将flip作为flip的函数。

    我们可以解析flip<sub>1</sub> flip<sub>2</sub>的类型(我这里用下标来明确我们指的是哪个flip)为:

    flip1 :: (a -> b -> c) -> b -> a -> c
    flip2 :: (d -> e -> f) -> e -> d -> f

    由于flip<sub>2</sub>flip<sub>1</sub>的参数,所以表示flip<sub>2</sub>的类型与flip<sub>1</sub>的参数类型相同,所以表示:

            a       -> (b ->    c    )
    ~ (d -> e -> f) -> (e -> (d -> f))

    因此这意味着a ~ (d -&gt; e -&gt; f)a 的类型与d -&gt; e -&gt; f 相同)、b ~ ec ~ (d -&gt; e)。所以函数flip<sub>1</sub> flip<sub>2</sub>的类型就是flip<sub>1</sub>的输出类型的类型,但是是等价的,也就是说:

    flip1 flip2 :: b -> a -> c
    flip1 flip2 :: e -> (d -> e -> f) -> (d -> e)

    因此,我们基本上创建了一个函数,它首先获取第二个参数,然后获取该函数,然后是第一个参数,然后使用翻转的参数调用该函数。所以如果flip2 = flip flip,它的实现如下:

    flip2 :: e -> (d -> e -> f) -> (d -> e)
    flip2 y f x = f x y

    【讨论】:

      猜你喜欢
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-03
      • 2012-04-03
      • 1970-01-01
      相关资源
      最近更新 更多