Я играл вокруг с 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 .) f = sum . f
Любые бинарные операторы могут быть записаны так, например, карта (7 -) [1,2,3] == [7-1, 7-2, 7-3]
.
Ответ КенниТМ отличный, но все же я хотел бы предложить другую точку зрения:
dotProduct = (.) (.) (.) sum (zipWith (*))
(.) f g
применяет f
к результату g
с одним аргументом(.) (.) (.) f g
применяет f
к результату g
при двух аргументах(.) (.) ((.) (.) (.)) f g
применяет f
к результату g
при трёх аргументах(.~) = (.) (.) (.)
, (.~~) = (.) (.) (.~)
, (.~~~) = (.) (.) (.~~)
и теперь let foo a b c d = [1..5]; (.~~~) сумма foo 0 0 0 0
приводит к 15
.
TypeCompose
Конала предоставляет синоним (.)
называется result
. Возможно, это название более полезно для понимания того, что происходит.
fmap
также работает вместо (.)
, если импортировать соответствующие экземпляры (import Control.Applicative
сделает это), но его тип более общий и, следовательно, возможно, более запутанный.