2010-06-26 159 views
13

我一直在用Haskell玩一下,包括以无点形式练习写作功能。下面是一个示例函数:为什么这个函数的免提版本看起来像这样?

dotProduct :: (Num a) => [a] -> [a] -> a 
dotProduct xs ys = sum (zipWith (*) xs ys) 

我想用无点形式写这个函数。下面是我在别处找到了一个例子:

dotProduct = (sum .) . zipWith (*) 

不过,我不明白为什么自由点的形式看起来像(sum .) . zipWith (*)而不是sum . zipWith (*)。为什么总括在括号内并且有2个组合运算符?

回答

19
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]

+0

这部分中的'* *'f * g ==(f *)g'与'.'函数组合相同吗? – guhou 2010-06-26 12:18:09

+0

@Bleu:是的。任何二元运算符都可以。 – kennytm 2010-06-26 12:32:56

13

KennyTM的答案是优秀的,但我仍想提供另一个视角:

dotProduct = (.) (.) (.) sum (zipWith (*)) 
  • (.) f g上给出一个说法
  • (.) (.) (.) f gg结果适用f上的结果适用fg给出两个参数
  • (.) (.) ((.) (.) (.)) 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中的更多详细信息
+0

感谢您的回答!我对Haskell仍然很陌生,所以这里有一些看起来......糟糕......但学习不同的方法也有帮助:) – guhou 2010-06-26 12:57:54

+2

'。(。)(。)(。)'的​​情况是很常见和直接的,所以我有时会创建一个'(...)运营商。除此之外,这可能是有意义的时候了。 – 2010-06-26 16:36:31

+1

太糟糕了...... ..被采取:D – 2010-06-27 05:08:08

相关问题