我编写了以下代码,它使用光泽库获取了一堆点并在屏幕上绘制它们。
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
它工作正常,但我发现有一个重复的模式:一系列函数调用,每个函数调用的结果都会输入到下一个参数的最后一个参数中。 所以我通过删除中间变量,反转顺序并用函数组合(“。”)链接函数来重构,如下所示:
let pict = Pictures . (map Line) . (map $ map $ mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
令人高兴的是,这也很好用。但我想知道我是否会降低可读性,或者我是不是习惯于阅读和阅读写点免费样式代码。另外,我如何推理这段代码?第二个版本更有效率,还是仅仅更高效?我有什么风格可以让它更清晰吗?
答案 0 :(得分:31)
一些快速建议:
let pict = Pictures . (map Line) . (map $ map $ mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
你有一些多余的东西可以直接删除:
let pict = Pictures . map Line . (map $ map mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
使用map (map mkPt)
字词无论如何都不会避开括号,所以要摆脱$
:
let pict = Pictures . map Line . map (map mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
为清晰起见,您可以在多行上编写合成链:
let pict = Pictures
. map Line
. map (map mkPt)
. blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict
do
块是多余的,因为它只有一个语句,您可以将最终应用程序移到定义之外:
let displayPict = displayInWindow "My Window" (200, 200) (10, 10) white
. Pictures
. map Line
. map (map mkPt)
. blocks
in displayPict pes
您可以合并两个map
:
let displayPict = displayInWindow "My Window" (200, 200) (10, 10) white
. Pictures
. map (Line . map mkPt)
. blocks
in displayPict pes
有时长链使用Control.Arrow
中的反向合成运算符也更具可读性:
let displayPict = blocks
>>> map (Line . map mkPt)
>>> Pictures
>>> displayInWindow "My Window" (200, 200) (10, 10) white
in displayPict pes
但所有这些都是可选的;让你的代码尝到品味。
关于效率问题,一旦GHC的优化程序通过代码,我认为没有理由认为两者会有所不同。
答案 1 :(得分:4)
点自由风格可以很好地清楚地表明函数只是输入上的一系列转换。读起来很容易:
foo = map show . doThis . doThat . etc
因为它看起来像典型的无点代码,所以熟悉它的人将能够确切地看到什么是重要的,没有噪音。将其与:
进行比较foo x = d
where
a = etc x
c = doThis b
b = doThat a
d = map show c
显然,这有点做作,但想法是需要阅读并密切注意额外的定义,以便了解foo
真正在做什么。 a
是否用作多个辅助函数的参数?那么b
呢?数据是否以意外的方式流过这些辅助函数?在这种情况下,点自由风格是说“事情正在变成一条管道,你不需要考虑的奇怪”
在其他情况下,无点样式可以真正混淆事物。通常情况下,当你打破let和wheres时。所以,简洁并不是唯一的目标,减少心理负担也很重要。 (正如其他人评论的那样,无点样式在优化代码中不应该有性能差异。)