Почему бессмысленная версия этой функции выглядит так? - PullRequest
13 голосов
/ 26 июня 2010

Я немного поигрался с Хаскеллом, включая отработку написания функций в бессмысленной форме.Вот пример функции:

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

Я хотел бы написать эту функцию в бессмысленной форме.Вот пример, который я нашел в другом месте:

dotProduct = (sum .) . zipWith (*)

Однако я не понимаю, почему форма без точек выглядит как (sum .) . zipWith (*) вместо sum . zipWith (*).Почему сумма в скобках и имеет 2 оператора композиции?

Ответы [ 2 ]

19 голосов
/ 26 июня 2010
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].

13 голосов
/ 26 июня 2010

Ответ KennyTM превосходен, но все же я хотел бы предложить другую точку зрения:

dotProduct = (.) (.) (.) sum (zipWith (*))
  • (.) f g применяется f к результату g с одним аргументом
  • (.) (.) (.) f g применяет f к результату g с двумя аргументами
  • (.) (.) ((.) (.) (.)) f g применяет f к результату g с учетом трех аргументов
  • ...
  • Может делать (.~) = (.) (.) (.), (.~~) = (.) (.) (.~), (.~~~) = (.) (.) (.~~) и теперь let foo a b c d = [1..5]; (.~~~) sum foo 0 0 0 0 приводит к 15.
    • Но я бы не стал этого делать. Это, вероятно, сделает код нечитаемым. Просто будь полной точкой.
  • Конал TypeCompose предоставляет синоним для (.), называемый result. Возможно, это имя более полезно для понимания того, что происходит.
    • fmap также работает вместо (.), если импортировать соответствующие экземпляры (import Control.Applicative сделает это), но его тип более общий и, следовательно, возможно, более запутанный.
  • Концепция Конала «слияние» (не путать с другими употреблениями «слияния») в некотором роде связана, и imho предлагает хороший способ составления функций. Подробнее в этом длинном Google Tech Talk, который дал Конал
...