haskell - 美丽而可怕的 haskell

标签 haskell functional-programming

haskell 很漂亮。这是事实。它简洁、快速等。你们中的许多人都会承认用它写作是一种极大的乐趣。另一方面,我认为当人们尝试编写过于复杂的代码时,它的简洁性可能是一个缺点。例如,我最近打开我 friend 的项目,发现了这样的内容:

stationDepartures id sc=map (\(s1,list)->(stationName $ (stationMap $ system sc) Map.! s1,list)) ( Map.toList (Map.fromListWith (++) (map (\((s1,s2),(d,start,dur))->(s2,[start])) (Map.toList (Map.filterWithKey (\(s1,s2) _ ->s1==id) (Map.unions (List.map times (Map.elems $ schedule sc))))))))

这句台词对我来说完全无法读懂。这当然是一个相当极端的例子,但它帮助我意识到也许我的 Haskell 代码对其他人来说可能难以阅读。我开始想知道在 Haskell 中创建漂亮代码的原则是什么。我发现例如有些人认为 lambda 函数是多余的,因为它们使代码的可读性较差。你对此有何看法? Haskell 代码应该满足什么要求才能被认为是“美丽的”?

最佳答案

我假设您问:“我怎样才能以更具可读性的方式写出这段单行文字?”否则这个问题就有点太主观了。

单行代码在任何语言中都是有问题的,尽管 Haskell 由于大量的二元运算符(具有优先级规则)、高阶函数(很难命名)和(惊呼!)高阶函数,问题尤其严重函数是二元运算符。然而,我们首先可以注意到,单行代码中的大多数括号都可以被消除,并且我们可以证明该表达式是一系列组合在一起的函数。每个函数都可以写在单独的行上,并由 . 组成,最后的 $ 将整个函数应用于参数。

stationDepartures id sc =
  map (\(s1,list) -> (stationName $ (stationMap $ system sc) Map.! s1,
                      list)) .
  Map.toList .
  Map.fromListWith (++) .
  map (\((s1,s2),(d,start,dur)) -> (s2,[start])) .
  Map.toList .
  Map.filterWithKey (\(s1,s2) _ -> s1 == id) .
  Map.unions .
  List.map times .
  Map.elems $ schedule sc

对我来说,这是相当可读的,因为我识别其中的模式,并且我可以从下到上跟踪数据流。 (注意:这就是为什么所有 Map 函数都将 Map 作为最后一个参数而不是第一个参数。当您使用设计你的 Haskell API!)

例如,Map.toList。 Map.fromListWith f 模式非常常见,只是很难在一行中看到它(至少在我看来)。该代码实际上并不是那么复杂,只是通过手术删除了换行符。

但是,可读性是主观的。

您将形成一种易于阅读的风格。随着您对语言的了解越来越多,风格将会演变,您对“美丽代码”的感觉也会演变。就让它发生吧,尽量不要陷入太多的重写中,这样你就不再有乐趣了。

关于haskell - 美丽而可怕的 haskell ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11128759/

相关文章:

通过递归检查尾部来迭代列表的性能

haskell - PolyKinds 的不明确类型

haskell - 如何在 Haskell 中进行 HTTPS 请求?

programming-languages - Scala "continuations"只是用于定义和使用回调函数的时髦语法吗?

python - 在给定相同参数的情况下,迭代 python 中的 lambda 函数列表

optimization - Haskell 中的严格性优化和内存分配

python - 在 python 中没有 for 循环的情况下重复函数几次

opengl - Haskell 图形程序关闭过早

haskell重定向

arrays - 在 F# 中实例化数组?