好的Haskell编码标准

有人可以提供一个良好的Haskell编码标准的链接? 我已经find这个和这个 ,但是他们还不够全面。 更不用说HaskellWiki包含了像“谨慎使用类”和“定义符号中缀标识符”这样的“gem”应该只留给图书馆作者。

真的很难的问题。 我希望你的答案有好的一面。 同时,这里是我在初学者的代码中发现的错误或其他恼人的事情的目录。 与Kornel Kisielewicz指出的Cal Tech风格页面有一些重叠。 我的一些build议是像HaskellWiki“gem”一样模糊和无用,但我希望至less这是更好的build议:-)

  • 格式化您的代码,使其适合80列。 (高级用户可能更喜欢87或88;除此之外,推动它。)

  • 不要忘记, let绑定和where子句创build一个定义的相互recursion嵌套, 而不是 一系列的定义。

  • 利用where子句,特别是看看已经在范围内的函数参数的能力(很好的模糊build议)。 如果你真的在寻找Haskell,你的代码应该比-bindings更多地使用-bindings。 let -bindings过多是未被重build的ML程序员或Lisp程序员的标志。

  • 避免多余的括号。 有些地方冗余的括号是特别冒犯的

    • ifexpression式的条件下(把你当作一个未被重build的C程序员来标记)

    • 围绕一个函数应用程序本身就是一个中缀运算符( 函数应用程序比任何中缀运算符都更紧密)的参数,这个事实应该被刻录到每一个Haskeller的大脑中,就像我们恐龙拥有APL的从右到左的扫描规则烧伤)

  • 在中缀运算符周围放置空格。 在每个逗号之后放置一个空格在一个元组文字中。

  • 在函数和它的参数之间加一个空格,即使参数是加了括号的。

  • 明智地使用$操作符来减less括号。 注意$和中缀之间的密切关系.

     f $ g $ hx == (f . g . h) x == f . g . h $ x 
  • 不要忽视内置的MaybeEithertypes。

  • if <expression> then True else False不要写if <expression> then True else False ; 正确的短语就是<expression>

  • 当你可以使用模式匹配时,不要使用headtail

  • 不要忽略中缀点运算符的function组合。

  • 仔细使用换行符。 换行可以提高可读性,但是有一个折衷:您的编辑器可能一次只显示40-50行。 如果您需要同时阅读和理解大型函数,则不能过分使用换行符。

  • 几乎总是比较喜欢那些以{- ... -}注释结尾的注释。 支持的评论可能适合大标题 – 就是这样。

  • 给每个顶级函数一个明确的types签名。

  • 在可能的情况下,alignment--行, =符号,甚至在相邻行中出现的括号和逗号。

  • 受GHC中心影响,我有一个非常温和的偏好使用camelCase导出的标识符和short_name与下划线为本地where或绑定的variables。

一些很好的经验法则:

  • 请咨询HLint ,以确保您没有冗余大括号,并且您的代码不是毫无意义的点满。
  • 避免重新创build现有的库函数。 Hoogle可以帮助您find它们。
    • 很多时候,现有的图书馆function比人们所要做的要普遍。 例如,如果你想要Maybe (Maybe a) -> Maybe a ,然后join做其他事情。
  • 有时参数命名和文档很重要。
    • 对于像replicate :: Int -> a -> [a]这样的函数来说,每个参数的作用都是非常明显的。
    • 对于一个接受多个相同types参数的函数,比如isPrefixOf :: (Eq a) => [a] -> [a] -> Bool ,参数的命名/logging更重要。
  • 如果一个函数只是为了另一个函数而存在,并且没有其他用处,并且/或者很难为其命名,那么它可能应该存在于调用者的where子句中而不是模块的作用域中。
    • 适当时使用Template-Haskell。
    • 捆绑的function,如zip3zipWith3zip4zipWith4等是非常meh。 改为使用ApplicativeZipList的样式。 你可能从来没有真正需要这样的function。
    • 自动派生实例。 派生包可以帮助你派生types的实例,例如Functor (只有一个正确的方法可以使types成为Functor一个实例)。
  • 更一般的代码有几个好处:
    • 这更有用,可重用。
    • 因为有更多的限制,所以不太容易出错。
      • 例如,如果你想编程concat :: [[a]] -> [a] ,并注意到它可以更加通用,如join :: Monad m => m (ma) -> ma 。 编程join时出现错误的空间较小,因为编程concat时可以错误地反转列表,并且在join中可以做的事情很less。
  • 在代码中的许多地方使用相同的monad变换器堆栈时,为其创build一个types同义词。 这将使得types更短,更简洁,并且更容易批量修改。
  • 当心“懒惰IO”。 例如, readFile在读取文件的时候并不真正读取文件的内容。
  • 避免缩进,以至于找不到代码。
  • 如果你的types在逻辑上是一个types的实例,把它作为一个实例。
    • 这个实例可以replace您熟悉的其他接口函数。
    • 注意:如果有多个逻辑实例,则为实例创buildnewtype-wrappers。
    • 使不同的实例保持一致。 如果列表Applicative行为像ZipList一样,那将会非常令人困惑/不好。

我build议看看这个风格检查 。

  • 我喜欢尽可能地通过做一些事情来尽可能地将function组织为无点式的组合,例如:

     func = boo . boppity . bippity . snd where boo = ... boppity = ... bippity = ... 
  • 我喜欢只使用($)来避免嵌套parens或长括号expression式

  • …我想我还有更多的在我身上,哦,好吧

我发现很好的降价文件,涵盖了haskell代码风格的几乎每一个方面。 它可以用作备忘单。 你可以在这里find它: 链接