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?
答案 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=10
或y="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'
无法访问x
和y
。它接收参数f
,并计算表达式g
。看不到x
或y
。
但是,g
本身就是一个函数,在where
的{{1}}子句中使用辅助等式定义。
您可以将flip'
完全视为像g x y = f y x
这样的顶级等式。因此flip'
是两个参数g
和x
的函数。它的y
g
和x
可以访问y
,而不是flip'
。在应用g
之前,这些参数的值不会存在,直到flip'
返回函数g
之后(如果有的话)。
在g
的{{1}}子句中定义where
的特殊之处在于它可以访问flip'
的参数,这是flip'
可以用g
定义的方式。
因此,当调用f
时,它会收到一个函数flip'
。对于f
的每个特定调用,它构造一个新函数flip'
。 g
会在调用时收到两个参数g
和x
,但尚未发生。 y
然后只返回flip'
作为结果。
答案 2 :(得分:1)
让我们找到g
的类型。
我们知道翻页类型:(a -> b -> c) -> (b -> a -> c)
因此,我们可以推断f
类型:(a -> b -> c)
我们对g
g x y = f y x
从右侧我们推导出y :: a
和x :: 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 块中定义函数。因此,变量x
和y
只是g
的形式参数,这就是您可以在g x y = f y x
中访问它的原因:g x y
定义形式参数x
和y
以及f y x
是g
的定义。最后,该定义从flip f = g
返回。
答案 4 :(得分:1)
在ghci上,一个简单的示例可以理解和说明:
Prelude> sub x y = x - y
Prelude> sub 3 1
2
Prelude> flip sub 3 1
-2