翻转功能如何工作?

时间:2013-01-18 10:38:46

标签: haskell

Haskell新手在这里。我正在通过了解你是一个haskell,并且遇到了翻转函数的这个定义。

flip' :: (a -> b -> c) -> (b -> a -> c)  
flip' f = g  
    where g x y = f y x

我不知道的是,x和y来自哪里?签名告诉我,flip'是一个函数,它接受一个函数(带有两个参数),并返回一个函数(同样,带有两个参数)。

如果我理解这一点,那么当我写一个像

这样的函数时
foo :: (a -> b) -> a -> b
foo f x = f x   -- applies the function f on x

但是,在这种情况下,我正在明确传递参数[ie x],因此我可以在函数体中访问它。那么为什么flip'函数可以访问参数x和y?

5 个答案:

答案 0 :(得分:36)

位于hackage.haskell.org的Prelude包中的base包含在每个Haskell文件中的隐式导入,其中找到了flip函数。在右侧,您可以点击“来源”,然后查看source code for flip

flip         :: (a -> b -> c) -> b -> a -> c
flip f x y   =  f y x

where子句允许本地定义,x=10y="bla"。您还可以使用与顶级语法相同的语法在本地定义函数。 add x y = x + y

在以下等效公式中,我进行了替换g = f y x

flip         :: (a -> b -> c) -> b -> a -> c
flip f x y   =  g
  where
    g = f y x

现在g不带任何参数。但是,如果我们将g定义为g a b = f b a,那么我们将会:

flip         :: (a -> b -> c) -> b -> a -> c
flip f x y   =  g x y
  where
    g a b = f b a

不,我们可以做一点代数取消(如果你认为它像数学类的代数那么你会非常安全)。专注于:

flip f x y   =  g x y

取消每一方的y:

flip f x   =  g x

现在取消x:

flip f   =  g

现在把它放回到完整的表达中:

flip     :: (a -> b -> c) -> b -> a -> c
flip f   =  g
  where
    g a b = f b a

作为最后一个整容步骤,我们可以将a替换为x,将b替换为y,以将函数恢复为参数名称:

flip     :: (a -> b -> c) -> b -> a -> c
flip f   =  g
  where
    g x y = f y x

正如你所看到的,翻转的这个定义是有点圆的,我们在前奏中开始的是简单的,我喜欢的定义。希望这有助于解释where如何工作以及如何对Haskell代码进行一些代数操作。

答案 1 :(得分:15)

flip'无法访问xy。它接收参数f,并计算表达式g。看不到xy

但是,g本身就是一个函数,在where的{​​{1}}子句中使用辅助等式定义。

您可以将flip'完全视为像g x y = f y x这样的顶级等式。因此flip'是两个参数gx的函数。它的y gx可以访问y,而不是flip'。在应用g之前,这些参数的值不会存在,直到flip'返回函数g之后(如果有的话)。

g的{​​{1}}子句中定义where的特殊之处在于它可以访问flip'的参数,这是flip'可以用g定义的方式。

因此,当调用f时,它会收到一个函数flip'。对于f的每个特定调用,它构造一个新函数flip'g会在调用时收到两个参数gx,但尚未发生。 y然后只返回flip'作为结果。

答案 2 :(得分:1)

让我们找到g的类型。

我们知道翻页类型:(a -> b -> c) -> (b -> a -> c)

因此,我们可以推断f类型:(a -> b -> c)

我们对g

有这个定义
g x y = f y x

从右侧我们推导出y :: ax :: b

因此g :: b -> a -> c

请注意,可以在没有'where'子句的情况下重写定义。

flip' f = g where g x y = f y x
-> flip' f a b = g a b where g a b = f b a
-> flip' f a b = f b a

答案 3 :(得分:1)

简而言之,您还可以在 where 块中定义函数。因此,变量xy只是g的形式参数,这就是您可以在g x y = f y x中访问它的原因:g x y定义形式参数xy以及f y xg的定义。最后,该定义从flip f = g返回。

答案 4 :(得分:1)

在ghci上,一个简单的示例可以理解和说明:

Prelude> sub x y = x - y
Prelude> sub 3 1
2
Prelude> flip sub 3 1
-2