良好的Haskell编码标准

时间:2009-12-30 23:23:16

标签: haskell coding-style conventions

有人可以为Haskell提供良好编码标准的链接吗?我找到了thisthis,但它们远非全面。更不用说HaskellWiki包含诸如“谨慎使用类”这样的“宝石”,“定义符号中缀标识符应仅留给图书馆作者。”

5 个答案:

答案 0 :(得分:90)

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

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

  • 不要忘记let绑定和where子句创建一个相互递归的定义嵌套, 序列定义

  • 利用where子句,特别是它们能够查看已经在范围内的函数参数(很好的模糊建议)。如果你真的是在使用Haskell,那么你的代码应该有更多where - 绑定而不是let - 绑定。太多let - 绑定是未经重构的ML程序员或Lisp程序员的标志。

  • 避免使用多余的括号。一些冗余括号特别令人反感的地方是

    • 围绕if表达式中的条件(将您视为未经重构的C程序员)

    • 围绕一个函数应用程序,它本身就是一个中缀运算符的参数(函数应用程序比任何中缀运算符更紧密。这个事实应该烧到每个Haskeller的大脑中,大致相同我们的恐龙让APL的从右到左的扫描规则被烧毁了。)

  • 在中缀运算符周围添加空格。在元组文字中的每个逗号后面加一个空格。

  • 首选函数及其参数之间的空格,即使参数是括号。

  • 明智地使用$运算符来减少括号。请注意$和中缀.之间的密切关系:

    f $ g $ h x == (f . g . h) x == f . g . h $ x
    
  • 不要忽视内置的MaybeEither类型。

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

  • 当您可以使用模式匹配时,请勿使用headtail

  • 不要忽略使用中缀点运算符的函数组合。

  • 仔细使用换行符。换行可以提高可读性,但需要权衡:您的编辑器一次只能显示40-50行。如果您需要同时阅读和理解大型功能,则不得过度使用换行符。

  • 几乎总是更喜欢在--条评论中运行到行尾的{- ... -}条评论。支撑的注释可能适用于大标题 - 就是它。

  • 为每个顶级函数指定一个显式类型签名。

  • 如果可能,请对齐--行,=符号,甚至是相邻行中出现的括号和逗号。

  • 受GHC中心的影响,我非常温和地使用camelCase表示导出的标识符,short_name使用下划线表示本地where - 绑定或{{ 1}} - 绑定变量。

答案 1 :(得分:27)

一些良好的拇指规则imho:

  • 咨询HLint以确保您没有多余的大括号,并且您的代码没有毫无意义的点。
  • 避免重新创建现有的库函数。 Hoogle可以帮助您找到它们。
    • 现有的库函数通常比人们的函数更通用。例如,如果您想要Maybe (Maybe a) -> Maybe a,那么join就可以做到这一点。
  • 有时,参数命名和文档很重要。
    • 对于像replicate :: Int -> a -> [a]这样的函数,每个参数的作用非常明显,仅从它们的类型开始。
    • 对于带有多个相同类型参数的函数,如isPrefixOf :: (Eq a) => [a] -> [a] -> Bool,参数的命名/记录更为重要。
  • 如果一个函数只存在于另一个函数中,并且没有其他用处,并且/或者很难想到它的好名字,那么它可能应该存在于它的调用者的where子句中而不是在模块的范围内。
  • DRY
    • 在适当的时候使用Template-Haskell。
    • zip3zipWith3zip4zipWith4等功能套件非常简单。使用Applicative样式代替ZipList。你可能从未真正需要这些功能。
    • 自动导出实例。 derive包可以帮助您为类型类派生实例,例如Functor(只有一种正确的方法可以使类型成为Functor的实例)。
  • 更通用的代码有几个好处:
    • 它更有用,可重复使用。
    • 由于存在更多限制,因此不容易出错。
      • 例如,如果您想对concat :: [[a]] -> [a]进行编程,请注意它如何更为通用join :: Monad m => m (m a) -> m a。编程join时出错的余地较小,因为在编程concat时,您可以错误地反转列表,在join中,您可以做的事情很少。
  • 在代码中的许多地方使用相同的monad变换器堆栈时,请为其创建类型同义词。这将使类型更短,更简洁,更容易批量修改。
  • 小心“懒惰的IO”。例如,readFile在读取文件时并不真正读取文件的内容。
  • 避免缩进,以至于找不到代码。
  • 如果您的类型在逻辑上是类型类的实例,请将其设为实例。
    • 该实例可以替换您熟悉的其他接口函数。
    • 注意:如果有多个逻辑实例,请为实例创建newtype-wrappers。
    • 使不同的实例保持一致。如果列表Applicative表现得像ZipList,那将会非常混乱/不好。

答案 2 :(得分:6)

我建议你看看style checker

答案 3 :(得分:6)

  • 我想尝试组织功能 作为无点风格的作品 做事尽可能多 像:

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

  • ......我以为我还有一些,哦,好吧

答案 4 :(得分:4)

我找到了好的降价文件,几乎涵盖了haskell代码风格的每个方面。它可以用作备忘单。您可以在此处找到它:link