我正在通过一些基本功能来学习Haskell。我正在使用Flip进行一些练习,该函数具有两个参数的功能,并通过翻转参数的顺序来评估结果。考虑功能 flip flip ,我会认为,按照flip的定义,它会将参数翻转了两次,并以原始顺序使用参数评估了原始功能。当我用ghci检查函数类型检查这个假设时,它产生了:
flip flip :: b->(a-> b-> c)-> a-> c
我不明白为什么这是翻转翻转的功能类型。它接受参数b和参数(a-> b-> c),并产生函数a-> c。为什么会这样呢?由于我对此一无所知,因此我将不胜感激。预先感谢
答案 0 :(得分:9)
翻转两次将是\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')
答案 1 :(得分:6)
让我们看看类型:
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
(.)
运算符将右侧的输出馈送到左侧。
答案 2 :(得分:4)
您不两次应用flip
函数。如果您想两次申请flip
,那么您正在寻找:
flip . flip :: (b -> a -> c) -> b -> a -> c
您在这里所做的是翻转 flip
函数。因此,它将flip
作为flip
的函数。
我们可以将flip1 flip2
的类型(我在这里使用下标来明确指出我们指的是flip
)解析为:
flip1 :: (a -> b -> c) -> b -> a -> c
flip2 :: (d -> e -> f) -> e -> d -> f
由于flip2
是flip1
的参数,因此这意味着flip2
的类型与flip1
的参数是相同的类型,因此意味着:
a -> (b -> c )
~ (d -> e -> f) -> (e -> (d -> f))
因此,这意味着a ~ (d -> e -> f)
(类型a
与d -> e -> f
相同),b ~ e
和c ~ (d -> e)
。因此,函数flip1 flip2
的类型是flip1
的输出类型的类型,但是具有等价关系,所以这意味着:
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