点免费代码更有效率,还是只是更简洁?

non*_*ont 25 refactoring haskell coding-style pointfree

我编写了以下代码,它使用光泽库获取了一堆点并在屏幕上绘制它们.

let s = blocks pes
    pts = map (map mkPt) s  {- stitches to points-}
    lines = map Line pts    {-points to lines -}
    pict = Pictures lines   {- lines to a picture -}
  in do  displayInWindow "My Window" (200, 200) (10, 10) white pict
Run Code Online (Sandbox Code Playgroud)

它工作正常,但我发现有一个重复的模式:一个函数调用链,每个函数调用的结果进入下一个参数的最后一个参数.所以我通过删除中间变量,反转顺序并使用函数组合(".")链接函数来重构,如下所示:

let pict = Pictures . (map Line) . (map $ map $ mkPt) . blocks $ pes
                in do  displayInWindow "My Window" (200, 200) (10, 10) white pict
Run Code Online (Sandbox Code Playgroud)

令人高兴的是,这也很好.但是我想知道我是否会降低可读性,或者我是不是习惯于阅读和编写点免费样式代码.另外,我如何推理这段代码?第二个版本更有效率,还是仅仅更高效?有什么我可以风格化的做法让它更清晰吗?

C. *_*ann 31

一些快速建议:

let pict = Pictures . (map Line) . (map $ map $ mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
Run Code Online (Sandbox Code Playgroud)

你有一些多余的东西可以直接删除:

let pict = Pictures . map Line . (map $ map mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
Run Code Online (Sandbox Code Playgroud)

无论如何你都没有避开括号map (map mkPt),所以摆脱$:

let pict = Pictures . map Line . map (map mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
Run Code Online (Sandbox Code Playgroud)

为清晰起见,您可以在多行上编写组合链:

let pict = Pictures 
         . map Line 
         . map (map mkPt) 
         . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
Run Code Online (Sandbox Code Playgroud)

do块是多余的,因为它只有一个语句,您可以将最终应用程序移动到定义之外:

let displayPict = displayInWindow "My Window" (200, 200) (10, 10) white
                . Pictures 
                . map Line 
                . map (map mkPt) 
                . blocks
in displayPict pes
Run Code Online (Sandbox Code Playgroud)

你可以合并两个maps:

let displayPict = displayInWindow "My Window" (200, 200) (10, 10) white
                . Pictures 
                . map (Line . map mkPt) 
                . blocks
in displayPict pes
Run Code Online (Sandbox Code Playgroud)

有时,长链使用反向合成运算符也更具可读性Control.Arrow:

let displayPict = blocks
                  >>> map (Line . map mkPt) 
                  >>> Pictures
                  >>> displayInWindow "My Window" (200, 200) (10, 10) white
in displayPict pes
Run Code Online (Sandbox Code Playgroud)

但所有这些都是可选的; 为你的代码品尝味道.

关于效率问题,一旦GHC的优化器通过代码,我认为没有理由认为两者会有所不同.

  • 实际上,生成的代码对于无点版本应该是相同的.没有任何优化,无点代码的效率会稍微降低,因为它有更多的函数调用(组合). (4认同)
  • @nont:没有`proc`符号的``s往往需要大量使用无点样式,因此有几个组合器很有用 - 只需在类型签名中读取`Arrow`实例为`( - >)`,例如`(箭头a)=> abc - > abd - > ab(c,d)`变为`(b - > c) - >(b - > d) - > b - >(c, d)`. (2认同)
  • 应该提到的是,let表达式不能用于任何目的,只是为了使它指向自由,整个事物可以写成`displayInWindow"My Window"(200,200)(10,10)white.图片 .地图(线.地图mkPt).阻止$ pes`. (2认同)
  • 此外,(>>>)由Control.Arrow导出,但它在Control.Category中定义.它也是在Category类上定义的,Arrow专门从这里开始.所有箭头实例分类,但反之亦然 - 镜头浮现在脑海中.总之,如果您不打算使用特定于Arrows的任何内容,我建议您直接使用Control.Category. (2认同)