你对Haskell感到满意需要多长时间?

时间:2008-12-18 07:00:23

标签: performance haskell

我是一个好的C / C ++程序员。我发现Haskell非常有趣。但在我看来,虽然编写干净的Haskell代码相对容易,因为它很好地模仿数学(我很熟悉),但很难在Haskell中编写运行速度快的干净代码。

快速版本的Haskell快速版本非常冗长且令人恐惧,与天真但短暂(两行),干净和直观的实现没有任何相似之处。 Haskell的长而可怕的版本实际上仍然比更短更简单的C计数器部分慢得多。

是因为当前的Haskell编译器太笨了还是凡人(当然不是SJP)编写快速的Haskell代码是不可能的?

5 个答案:

答案 0 :(得分:59)

你问两个不同的问题:学习和表现。

  • 我花了大约一个月的时间来熟悉使用递归,模式匹配,mapfilterfold的函数式编程。我用ML做了所有这些,但它很容易翻译成Haskell。
  • 我花了两三年时间把头包裹在monad周围,但那是因为我读错了东西。我认为现在有更好的教程。但如果你刚开始,请避开monads一段时间。
  • 我花了几个月的时间来创建来创建新类型,但使用现有的类很容易。
  • 我仍然不确定我是否拥有懒惰评估。但我喜欢Haskell的纯洁,倾向于将懒惰的评价视为一种不幸的事故,只有少数人(如John Hughes)知道如何利用。

你观察到性能问题只是因为你已经采用了一种加载了变异的算法,Tony Hoare为命令式语言设计了这种算法,并试图转化为Haskell。在Haskell中,与任何其他功能语言一样,昂贵的操作是分配 。尝试编写合并排序,您会发现它非常简单并且表现非常出色。

您如何避免将来犯同样的错误?看看Chris Okasaki的书Purely Functional Data Structures。很棒的书,它将帮助你学习“功能性的做事方式”,而不会放弃表现。

答案 1 :(得分:21)

有一个非常具体的原因,为什么快速排序在Haskell中不那么快。这是一个像神一样的算法的例子,其中有很好的hackery编织成它的工作原理 - 在这种情况下我的意思是hackery是一种真正的Haskell奉献者会认为是不必要的危险和非数学的技术。最初的实现尽一切努力打破Haskell对自身施加的规则:真正的快速排序通过用新信息覆盖存储槽来实现。在Haskell中这非常痛苦,因为它可以更容易地创建现有信息的全新副本。

因此,虽然那个天真的两行Haskell版本捕获了快速排序的本质(它进行了相同数量的密钥比较),但它并不是真正的快速排序。它缺少了进入它的大部分天才,它充分利用了调整现有值状态的能力。因此,它会生成大量的列表中间副本。

推测:Haskell编译器是否可以分析您的代码,应用与Hoare(quicksort的发明者)相同的推理,并找出它可以通过以有状态的方式完全重新实现它来优化它?可能。

答案 2 :(得分:13)

重点不是编写快速的Haskell代码,而是快速编写Haskell代码。当你到达那里并且需要快速编写代码(呃)时,开始优化(或使用FFI,你不必忘记你的C ++技能)。在Haskell中,您首先要寻求优雅,可靠和可维护性。我会为我的Haskell-fu添加分析,因此您不要浪费时间来优化未使用的分析。请记住不要过早优化。

答案 3 :(得分:8)

因此,要回答标题中的问题,您可能会在短时间内感受到Haskell基础知识。特别是如果您已经熟悉函数式编程。真正让Haskell脱颖而出的东西,比如懒惰,类型类,类型族,当然还有可怕的monad(和箭头)可能需要更多时间来理解和习惯。学习语言有很好的资源,许多是免费提供的,还有一个乐于助人的社区,所以我说你可能会在一两个半严肃的学习中感觉舒服; - )< / p>

我认为这是值得的,就像有些人认为学习Lisp一样值得学习,即使你从来没有真正用它来做任何事情。这是值得的,因为它让你成为一个更好的程序员 - 它会让你有不同的想法。我认为Haskell有类似的效果。

答案 4 :(得分:4)

原因是计算机的数学基础不同于Haskell的数学基础和一般的函数式语言。

要了解编译器面临的问题...将Haskell程序转换为C,尽可能保持原始状态,然后尝试优化该C代码(不用C语言从头开始重写)

这并不愚蠢,但功能语言并不是为了表现,而简洁的数学简单符号并非免费。