关于性能:你适应Haskell需要多长时间?

How long does it take for you to be comfortable with Haskell?

我是一个OK C/C++程序员。我觉得哈斯克尔很有趣。但在我看来,虽然写干净的haskell代码相对容易,因为它很好地模仿了数学(我很熟悉),但用运行速度很快的haskell写干净的代码是非常困难的。

快速版本的Quicksort的haskell是非常长和可怕的,它与简单但短(两行),干净和直观的实现没有相似之处。长而可怕的版本的haskell实际上仍然比短而简单的C计数器部分慢得多。

是因为当前的haskell编译器太笨了,还是人类(当然除了sjp)根本不可能快速编写haskell代码?


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

  • 我花了大约一个月时间才熟悉使用递归、模式匹配、mapfilterfold的函数编程。我用ML做了所有这些,但它很容易翻译成haskell。
  • 我花了两三年的时间才把我的脑袋放在单子上,但那是因为我读错了东西。我觉得现在有更好的教程。但如果你刚开始的话,暂时不要使用单子。
  • 我花了几个月的时间才能很好地创建新类型的类,但是使用现有的类是很容易的。
  • 我仍然不确定我是否有懒惰的评价。但我喜欢哈斯凯尔的纯洁性,并倾向于把懒惰的评价看作是一个不幸的意外,只有少数人(如约翰休斯)知道如何利用。

你观察到了一个性能问题,仅仅是因为你采用了一个加载了突变的算法,这是TonyHoare为命令式语言设计的,并试图将其转换为haskell。在haskell中,与其他任何函数语言一样,昂贵的操作是分配。试着写一个合并排序,你会发现它很简单而且性能很好。

你如何避免将来犯类似的错误?看看克里斯·冈崎的书《纯功能数据结构》。伟大的书,它将帮助你学习"实用的做事方式",而不放弃表现。


有一个非常具体的原因,为什么在哈斯克尔流沙不是那么快。这是一个类似上帝的算法的例子,它将出色的黑客技术融入到了它的工作方式中——我在本例中所指的黑客是一种真正的哈斯克尔信徒认为不必要的危险和非数学的技术。最初的实现尽一切努力打破haskell强加给自己的规则:真正的Quicksort通过用新信息覆盖存储槽来工作。在haskell做这件事是非常痛苦的,因为它发现制作现有信息的全新副本要容易得多。

因此,尽管简单的两行haskell版本捕获了Quicksort的本质(它进行相同数量的关键比较),但它并不是真正的Quicksort。它缺少一大部分进入它的天才,这充分利用了调整现有价值状态的能力。因此,它制作了大量列表的中间副本。

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


重点不是快速编写haskell代码,而是快速编写haskell代码。当你到达那里,你需要使你的代码快(ER),开始优化(或使用FFI,你不必忘记你的C++技能)。在Haskell中,您首先要寻找优雅、可靠和可维护性。我会在我的haskell fu中添加配置文件,这样你就不会浪费时间优化那些没有使用的。记住不要过早优化。


所以,要回答标题中的问题,你很可能会在短时间内对哈斯克尔的基础知识感到相当自在。尤其是如果你已经熟悉了函数式编程。真正让哈斯凯尔脱颖而出的东西,如懒惰、类型类、类型族,当然,可怕的单子(和箭头)可能需要更多的时间来理解和习惯。有很好的学习语言的资源,很多是免费提供的,还有一个有帮助的社区,所以我想说,在半认真学习的一两周内,你很可能会感觉很舒服。

不过,我认为这是值得的,就像有些人认为学习Lisp是值得的,即使你永远不会把它用于任何事情。这是值得的,因为它让你成为一个更好的程序员——它让你有不同的想法。我认为哈斯克尔也有类似的效果。


这是因为计算机的数学基础不同于哈斯克尔和函数语言的数学基础。

要了解编译器面临的问题…把haskell程序翻译成c,尽可能接近原始代码,然后尝试优化c代码(不需要用c-way从头重写)

它不是哑的,但是函数语言不是为了性能而设计的,简洁的数学简单符号也不是免费的。