2010-06-26 158 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

相關問題