13

ポイントフリー形式での書き込み関数の練習など、Haskell をかなりいじっています。関数の例を次に示します。

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

この関数をポイントフリー形式で書きたいと思います。他の場所で見つけた例を次に示します。

dotProduct = (sum .) . zipWith (*)

(sum .) . zipWith (*)しかし、ポイントフリーフォームが の代わりに のように見える理由がわかりませんsum . zipWith (*)。sum が角かっこで囲まれ、合成演算子が 2 つあるのはなぜですか?

4

2 に答える 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]

于 2010-06-26T11:59:15.923 に答える
13

KennyTM の答えは素晴らしいですが、それでも別の視点を提供したいと思います。

dotProduct = (.) (.) (.) sum (zipWith (*))
  • (.) f g指定された1 つの引数fの結果に適用されますg
  • (.) (.) (.) f g与えられた 2 つの引数fの結果に適用されますg
  • (.) (.) ((.) (.) (.)) f g与えられた 3 つの引数fの結果に適用されますg
  • ...
  • ができ(.~) = (.) (.) (.)、結果は になり(.~~) = (.) (.) (.~)まし(.~~~) = (.) (.) (.~~)た。 let foo a b c d = [1..5]; (.~~~) sum foo 0 0 0 015
    • しかし、私はそれをしません。おそらくコードが読めなくなります。ポイントいっぱいにしてください。
  • Conal'sは、 calledTypeComposeのシノニムを提供します。おそらく、この名前は何が起こっているのかを理解するのに役立ちます。 (.)result
    • fmapの代わりに(.)、関連するインスタンスをインポートする場合にも機能しますが (import Control.Applicativeそうするでしょう)、そのタイプはより一般的であり、おそらくより混乱を招きます。
  • Conalの「融合」の概念(「融合」の他の使用法と混同しないでください)は一種の関連性があり、私見は関数を構成するための優れた方法を提供します。詳細については、Conal が提供したこの長い Google Tech Talk をご覧ください
于 2010-06-26T12:35:06.173 に答える