40

Haskell新手在这里。我正在通过 Learn you a 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呢?

4

5 回答 5

43

Prelude位于 hackage.haskell.org 的基本中,包含在每个 Haskell 文件中的隐式导入中,即找到翻转函数的位置。在右侧,您可以单击“源”并查看翻转的源代码

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 没有参数。但是如果我们也定义了 gg 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

作为最后的修饰步骤,我们可以替换atoxbtoy以将函数恢复为参数名称:

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

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

于 2013-01-18T11:22:23.890 回答
17

flip'不访问xand y。它接收一个参数f,并计算为表达式g。没有xy在视线范围内。

然而,g它本身就是一个函数,在 的where子句中用一个辅助方程定义flip'

您可以g x y = f y x准确地阅读它,就好像它是一个顶级方程一样flip'g两个参数的函数也是如此,x并且y。它g可以访问xand y,而不是flip'。这些参数的值在应用之前不存在g,直到 afterflip'返回函数g(如果有的话)。

在of 子句中g定义的特殊之处在于它可以访问 的参数,这就是如何根据 来定义的。whereflip'flip'gf

因此,当flip'被调用时,它会收到一个函数f。对于 的每次特定调用flip',它都会构造一个新函数gg将收到两个参数,x并且y,当它被调用时,但这还没有发生。flip'然后返回g结果。

于 2013-01-18T10:52:36.830 回答
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
于 2013-01-18T10:50:23.897 回答
1

简而言之,您还可以在where块中定义函数。所以变量xy只是 的形式参数g,这就是为什么您可以在 中访问它的原因g x y = f y xg x y定义形式参数xyf y x是做什么的定义g。最后,该定义从flip f = g.

于 2017-01-01T04:50:28.923 回答
1

一个简单的例子来理解和说明,在你的 ghci 上做:

Prelude> sub x y = x - y
Prelude> sub 3 1
2
Prelude> flip sub 3 1
-2
于 2020-10-05T07:52:55.037 回答