为什么这个函数的pointfree版本看起来像这样?

guh*_*hou 13 haskell pointfree

我一直在玩Haskell,包括练习以无点形式编写函数.这是一个示例函数:

dotProduct :: (Num a) => [a] -> [a] -> a
dotProduct xs ys = sum (zipWith (*) xs ys)
Run Code Online (Sandbox Code Playgroud)

我想以无点形式编写这个函数.这是我在其他地方找到的一个例子:

dotProduct = (sum .) . zipWith (*)
Run Code Online (Sandbox Code Playgroud)

但是,我不明白为什么无点形式看起来像(sum .) . zipWith (*)而不是sum . zipWith (*).为什么括号中的和有2个组合运算符?

ken*_*ytm 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
Run Code Online (Sandbox Code Playgroud)

(sum .)是一节.它被定义为

(sum .) f = sum . f
Run Code Online (Sandbox Code Playgroud)

任何二元运算符都可以这样写,例如map (7 -) [1,2,3] == [7-1, 7-2, 7-3].


yai*_*chu 13

KennyTM的答案非常好,但我还想提供另一个观点:

dotProduct = (.) (.) (.) sum (zipWith (*))
Run Code Online (Sandbox Code Playgroud)
  • (.) f g适用fg给定一个参数的结果
  • (.) (.) (.) f g适用fg给定两个参数的结果
  • (.) (.) ((.) (.) (.)) f g适用fg给定三个参数的结果
  • ...
  • 可以做(.~) = (.) (.) (.),(.~~) = (.) (.) (.~),(.~~~) = (.) (.) (.~~)现在let foo a b c d = [1..5]; (.~~~) sum foo 0 0 0 0导致15.
    • 但我不会这样做.它可能会使代码无法读取.只是满满一点.
  • Conal TypeCompose提供了(.)被叫的同义词result.也许这个名字对于了解正在发生的事情更有帮助.
    • fmap(.)如果导入相关实例(import Control.Applicative会这样做),也可以代替,但它的类型更通用,因此可能更令人困惑.
  • Conal的"融合"概念(不要与"融合"的其他用法混淆)是一种相关的,imho提供了一种很好的组合功能的方法.Conal给出的这篇漫长的Google Tech Talk的更多细节

  • `(.)(.)(.)`的​​情况很常见,很简单,我有时会为它创建一个`(...)`运算符.除此之外,它可能是有点时间的. (2认同)