为什么这个函数的免提版本看起来像这样?
我一直在用Haskell玩一下,包括以无点形式练习写作功能。下面是一个示例函数:为什么这个函数的免提版本看起来像这样?
dotProduct :: (Num a) => [a] -> [a] -> a
dotProduct xs ys = sum (zipWith (*) xs ys)
我想用无点形式写这个函数。下面是我在别处找到了一个例子:
dotProduct = (sum .) . zipWith (*)
不过,我不明白为什么自由点的形式看起来像(sum .) . zipWith (*)
而不是sum . zipWith (*)
。为什么总括在括号内并且有2个组合运算符?
dotProduct xs ys = sum (zipWith (*) xs ys) -- # definition
dotProduct xs = \ys -> sum (zipWith (*) xs ys) -- # f x = g <=> f = \x -> g
= \ys -> (sum . (zipWith (*) xs)) ys -- # f (g x) == (f . g) x
= sum . (zipWith (*) xs) -- # \x -> f x == f
= sum . zipWith (*) xs -- # Precedence rule
dotProduct = \xs -> sum . zipWith (*) xs -- # f x = g <=> f = \x -> g
= \xs -> (sum .) (zipWith (*) xs) -- # f * g == (f *) g
= \xs -> ((sum .) . zipWith (*)) xs -- # f (g x) == (f . g) x
= (sum .) . zipWith (*) -- # \x -> f x == f
的(sum .)
是一个截面。它定义为
(sum .) f = sum . f
任何二元运算符都可以这样写, map (7 -) [1,2,3] == [7-1, 7-2, 7-3]
。
KennyTM的答案是优秀的,但我仍想提供另一个视角:
dotProduct = (.) (.) (.) sum (zipWith (*))
-
(.) f g
上给出一个说法 -
(.) (.) (.) f g
的g
结果适用f
上的结果适用f
g
给出两个参数 -
(.) (.) ((.) (.) (.)) f g
适用f
对的结果个三个参数 - ...
- 可以做
(.~) = (.) (.) (.)
,(.~~) = (.) (.) (.~)
,(.~~~) = (.) (.) (.~~)
现在let foo a b c d = [1..5]; (.~~~) sum foo 0 0 0 0
结果15
。- 但我不会这样做。它可能会使代码不可读。只是点满。
- Conal的
TypeCompose
提供了一个名为result
为(.)
的代名词。也许这个名字对于理解正在发生的事情更有帮助。-
fmap
也可代替(.)
,如果进口的有关情况(import Control.Applicative
将做到这一点),但它的类型就比较一般了,因此也许更令人困惑。
-
- Conal的“融合”概念(不要与“融合”的其他用法混淆)是一种相关的,imho提供了一种很好的方式来组成功能。在this long Google Tech Talk that Conal gave中的更多详细信息
感谢您的回答!我对Haskell仍然很陌生,所以这里有一些看起来......糟糕......但学习不同的方法也有帮助:) – guhou 2010-06-26 12:57:54
'。(。)(。)(。)'的情况是很常见和直接的,所以我有时会创建一个'(...)运营商。除此之外,这可能是有意义的时候了。 – 2010-06-26 16:36:31
太糟糕了...... ..被采取:D – 2010-06-27 05:08:08
这部分中的'* *'f * g ==(f *)g'与'.'函数组合相同吗? – guhou 2010-06-26 12:18:09
@Bleu:是的。任何二元运算符都可以。 – kennytm 2010-06-26 12:32:56