Function Haskell:应用两次翻转(翻转类型)

Function Haskell:应用两次翻转(翻转类型),function,haskell,functional-programming,Function,Haskell,Functional Programming,我正在学习Haskell的一些基本函数。我用Flip做了一些练习,它接受两个参数的函数,并根据参数的顺序计算结果。考虑函数翻转翻转< /强>,我会想到,按照翻转的定义,它翻转了两次参数,用原始顺序中的参数来评估原始函数。当我用ghci检查函数类型来检查这个假设时,它产生了: 翻转:b->(a->b->c)->a->c 我不明白为什么这是flip的功能类型。它接受参数b和参数(a->b->c)并生成函数a->c。为什么会这样?我真的很想得到一个解释,因为我对此一无所知。提前感谢翻动两次将是\f->

我正在学习Haskell的一些基本函数。我用Flip做了一些练习,它接受两个参数的函数,并根据参数的顺序计算结果。考虑函数<强>翻转翻转< /强>,我会想到,按照翻转的定义,它翻转了两次参数,用原始顺序中的参数来评估原始函数。当我用ghci检查函数类型来检查这个假设时,它产生了:

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


我不明白为什么这是flip的功能类型。它接受参数b和参数(a->b->c)并生成函数a->c。为什么会这样?我真的很想得到一个解释,因为我对此一无所知。提前感谢

翻动两次将是
\f->flip(flip f)
,或
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')
您不会两次应用
翻转
功能。如果要应用两次
翻转
,请查找:

flip . flip :: (b -> a -> c) -> b -> a -> c
由于
flip2
flip1
的参数,因此这意味着
flip2
的类型与
flip1
的参数类型相同,因此这意味着:

        a       -> (b ->    c    )
~ (d -> e -> f) -> (e -> (d -> f))
flip1 flip2 :: b -> a -> c
flip1 flip2 :: e -> (d -> e -> f) -> (d -> e)
因此,这意味着
a~(d->e->f)
(类型
a
d->e->f
)相同,
b~e
c~(d->e)
。因此,函数
flip1 flip2
的类型是
flip1
的输出类型,但具有等效性,因此这意味着:

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

让我们看看这些类型:

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

()
操作符将右侧的输出输入到左侧。

如果不翻转两次,可以翻转
翻转
功能。为了好玩,请尝试一下
翻转
。谢谢您简洁的回答。我意识到我还没有完全明白一件事(很抱歉,如果这个问题听起来很琐碎,但我对Haskell是完全陌生的)。为什么要匹配“b=b'”而不是“b=(b'->a')”然后再匹配“c=c'”?为什么第一个关联是有效的,而不是我给出的另一个?因为
->
语法具有正确的关联性。明确地说,类型是
((a->(b->(c)))->(b->(a->(c)))
。Haskell中的所有函数实际上都是一元函数(只接受一个参数),它们可能会返回另一个再次接受另一个参数的函数。类型
(b'->(a'->c')
不同于
((b'->a')->c')
,它们只是不匹配。