【问题标题】:Why does the pointfree version of this function look like this?为什么这个函数的pointfree版本看起来像这样?
【发布时间】:2010-06-26 11:53:09
【问题描述】:

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

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

我想以无点形式编写此函数。这是我在其他地方找到的示例:

dotProduct = (sum .) . zipWith (*)

但是,我不明白为什么无点表单看起来像 (sum .) . zipWith (*) 而不是 sum . zipWith (*)。为什么 sum 在括号中,并且有 2 个组合运算符?

【问题讨论】:

    标签: haskell pointfree


    【解决方案1】:
    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].

    【讨论】:

    • 这部分的*f * g == (f *) g.的函数组成一样吗?
    • @Bleu:是的。任何二元运算符都可以。
    【解决方案2】:

    KennyTM 的回答非常好,但我还是想提供另一种观点:

    dotProduct = (.) (.) (.) sum (zipWith (*))
    
    • (.) f gf 应用于g 给定一个参数的结果
    • 在给定两个参数的情况下,(.) (.) (.) f gf 应用于 g 的结果
    • (.) (.) ((.) (.) (.)) f g 在给定三个参数的情况下将 f 应用于 g 的结果
    • ...
    • 可以执行(.~) = (.) (.) (.)(.~~) = (.) (.) (.~)(.~~~) = (.) (.) (.~~) 和现在let foo a b c d = [1..5]; (.~~~) sum foo 0 0 0 0 的结果为15
      • 但我不会这样做。它可能会使代码不可读。点到为止。
    • Conal 的TypeCompose 提供了(.) 的同义词result。也许这个名字更有助于理解正在发生的事情。
      • fmap 也可以代替 (.),如果导入相关实例(import Control.Applicative 会这样做),但它的类型更通用,因此可能更令人困惑。
    • Conal 的“融合”概念(不要与“融合”的其他用法混淆)有点相关,恕我直言,提供了一种组合函数的好方法。更多详情this long Google Tech Talk that Conal gave

    【讨论】:

    • 感谢您的回答!我对 Haskell 还是很陌生,所以其中一些看起来.. 神秘.. 但学习不同的方法也很有帮助 :)
    • (.) (.) (.) 的情况很常见也很简单,我有时会为它创建一个(...) 运算符。不过,除此之外,可能是时候变得有意义了。
    猜你喜欢
    • 2017-06-17
    • 1970-01-01
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 2018-06-08
    • 1970-01-01
    • 2011-04-29
    相关资源
    最近更新 更多