关于Haskell中函数组合的困惑

时间:2011-08-02 13:47:23

标签: haskell function-composition pointfree

考虑使用ghci中的函数定义。

let myF = sin . cos . sum 

其中,。代表两个函数的组合(右关联)。我可以打电话给

myF [3.14, 3.14]

它给了我想要的结果。显然,它将list [3.14,3.14]传递给函数'sum',并将其'result'传递给cos,依此类推。但是,如果我在翻译中这样做

let myF y = sin . cos . sum y 

let myF y = sin . cos (sum y) 
然后我遇到了麻烦。将此修改为以下内容可以得到我想要的结果。

let myF y = sin . cos $ sum y 

let myF y = sin . cos . sum $ y 

(。)的类型表明下面的形式应该没有问题,因为'sum y'也是一个函数(不是吗?After-all一切都是Haskell中的一个函数?)

let myF y = sin . cos . sum y -- this should work?

更有趣的是,我可以使用两个(或许多)参数(想想将列表[3.14,3.14]作为两个参数x和y),我必须写下面的

let (myF x) y = (sin . cos . (+ x)) y 
myF 3.14 3.14 -- it works! 
let myF = sin . cos . (+) 
myF 3.14 3.14 -- -- Doesn't work!

关于这种形式的HaskellWiki有一些讨论他们称之为'PointFree'形式http://www.haskell.org/haskellwiki/Pointfree。通过阅读本文,我怀疑这种形式与两个lambda表达式的组合不同。当我尝试绘制一条分隔这两种风格的线时,我感到很困惑。

3 个答案:

答案 0 :(得分:9)

让我们看一下types。对于sincos,我们有:

cos, sin :: Floating a => a -> a

sum

sum :: Num a => [a] -> a

现在,sum y将其转换为

sum y :: Num a => a

这是一个值,而不是一个函数(你可以将它命名为一个没有参数的函数,但这非常棘手,你还需要命名() -> a函数 - 在某个地方讨论过这个但是我现在找不到链接 - Conal谈到它。)

无论如何,尝试cos . sum y将无效,因为.期望双方都有类型a -> bb -> c(签名为(b -> c) -> (a -> b) -> (a -> c))和{{ 1}}无法用这种风格书写。这就是为什么你需要包括括号或sum y

对于无点样式,简单的翻译方法是:

  • 将函数移动并将函数的最后一个参数移动到由函数应用程序分隔的表达式的末尾。例如,如果$我们最后有mysum x y = x + y,但我们现在无法将其删除。相反,重写为y它有效。
  • 删除所说的论点。在我们的案例中mysum x y = (x +) y
  • 重复,直到你没有更多的参数。这里mysum x = (x +)

(我选择了一个简单的例子,对于更复杂的案例,你必须使用mysum = (+)和其他人)

答案 1 :(得分:6)

不,sum y不是一个功能。这是一个数字,就像sum [1, 2, 3]一样。因此,完全可以理解您不能使用函数组合运算符(.)

并非Haskell中的所有功能都是功能。

答案 2 :(得分:3)

强制性的含义是:(空格)比.更紧密地绑定

Haskell中的大多数空格可以被认为是一个非常高的固定性$(“应用”功能)。 w x . y z(w $ x) . (y $ z)

基本相同

当您第一次了解$.时,您还应该确保了解(空格),并确保您了解语言语义是如何隐式括起来的事情可能不会(乍一看)显得直观。