与函数组合混淆

Confusion with function composition

开始学习Haskell:

*Main> map double [1,2,3]
[2,4,6]

*Main> sum (map double [1,2,3])
12

*Main> (sum . map) (double) ([1,2,3])

<interactive>:71:8:
Couldn't match type ‘[b0] -> [b0]’ with ‘[[t0] -> t]’
Expected type: (b0 -> b0) -> [[t0] -> t]
  Actual type: (b0 -> b0) -> [b0] -> [b0]
Relevant bindings include it :: t (bound at <interactive>:71:1)
Probable cause: ‘map’ is applied to too few arguments
In the second argument of ‘(.)’, namely ‘map’
In the expression: sum . map

根据这个答案:Haskell: difference between . (dot) and $ (dollar sign) "The primary purpose of the . operator is not to avoid parenthesis, but to chain functions. It lets you tie the output of whatever appears on the right to the input of whatever appears on the left."。

好的,为什么我的示例不起作用?实际类型和预期类型不同,但为什么呢?毕竟,根据这个描述 map 应该在输入上采用 (double) ([1,2,3]) 并将其输出传递给 sum 的输入?

原因是 . 只允许函数在传递给下一个之前使用 一个 参数。所以:

(sum . map) double [1,2,3]

会变成

(sum (map double)) [1,2,3]

...我们不能对一个函数求和,对吗?大量输入错误!

您要做的是:

(sum . map double) [1,2,3]

减少为:

sum (map double [1,2,3])

如果你想看,.是这样定义的:

(.) :: (b -> c) -> (a -> b) -> (a -> c)
(.) f g arg = f (g arg)

如果你真的很聪明,你可以双重组合一些东西,这样它在传递之前需要两个参数:

((sum .) . map) double [1,2,3]

减少为:

(sum . map double) [1,2,3]

最后:

sum (map double [1,2,3])