目前,我正在尝试通过“学习您的Haskell”一书来学习Haskell,并且试图了解chapter 5中flip
函数的实现。问题在于作者声明如果g x y = f y x
有效,则f y x = g x y
也必须为真。但是这种反转如何以及为什么会影响两个函数定义?
我知道currying的工作方式,并且我也知道->
运算符在默认情况下是右关联的,因此类型声明实际上是相同的。我也了解彼此分开的功能,但不了解g x y = f y x
的反转与此相关。
第一个翻转功能
flip' :: (a -> b -> c) -> (b -> a -> c)
flip' f = g
where g x y = f y x
第二次翻转功能
flip' :: (a -> b -> c) -> b -> a -> c
flip' f y x = f x y
答案 0 :(得分:7)
我认为作者脑海中的论点被粗略地缩写为一点都不合理。但是这是我对推理的猜测。我们从第一个定义开始:
flip f = g where g x y = f y x
现在,我们观察到这是一件令人毛骨悚然的事情,并且我们使用(->)
和垃圾的所有关联性讨论来写相同的东西,但是对f
有两个额外的论点。像这样:
flip f x y = g x y where g x y = f y x
现在我们得到了他双向调用的方程:g x y = f y x
,反之亦然。我们可以使用以下公式重写flip
的主体,如下所示:
flip f x y = f y x where g x y = f y x
由于定义的正文不再提及g
,因此我们可以将其删除。
flip f x y = f y x
现在我们几乎在那里。在最终定义中,作者在各处交换了名称x
和y
。我不知道他们为什么选择这么做,但这是您可以在方程式推理中做出的合法举动,所以在那里没有问题。这样做为我们提供了最终方程:
flip f y x = f x y
答案 1 :(得分:3)
flip
接受一个函数并返回该函数的翻转版本。定义flip'
的一种方法是将应用程序包含在定义本身中,因为
flip' f y x = f x y ===> flip' f y = \x -> f x y
===> flip' f = \y -> \x -> f x y
也就是说,flip' f
是一个将f
以相反顺序应用于其自变量的函数。
第二个定义只是简单地给匿名函数\y -> \x -> f x y
命名,然后使用该名称作为flip' f x y
的定义。
===> flip' f = g where g = \y -> \x -> f x y
===> flip' f = g where g y = \x -> f x y
===> flip' f = g where g y x = f x y
也就是说,flip' f
是某个函数g
,其中g
被定义为以相反的顺序将f
应用于g
的自变量。>
定义g x y = f y x
和g y x = f x y
等效于alpha conversion。在这两种情况下,f
都是g
定义中的自由变量; g
作为对f
的{{1}}参数的闭包。