34

我是一个不错的 C/C++ 程序员。我发现 Haskell 非常有趣。但在我看来,尽管编写干净的 Haskell 代码相对容易,因为它很好地模仿了数学(我对此非常满意),但在 Haskell 中编写运行速度快的干净代码却非常困难。

更快的 Haskell 快速排序版本非常长且可怕,它与幼稚但短(两行)、干净且直观的实现没有相似之处。长而可怕的 Haskell 版本实际上仍然比更短更简单的 C 对应部分慢得多。

是因为当前的 Haskell 编译器太笨了,还是普通人(当然 SJP 除外)无法编写快速的 Haskell 代码?

4

5 回答 5

61

You ask two different questions: learning and performance.

  • It took me about a month to become comfortable with functional programming using recursion, pattern matching, map, filter, and fold. I did all that with ML but it translated to Haskell very easily.
  • It took me two or three years to wrap my head around monads, but that's because I read the wrong stuff. I think there are better tutorials now. But if you're beginning, avoid monads for a while.
  • It took me several months to get good at creating new type classes, but using the existing ones was easy.
  • I'm still not sure I have the hang of lazy evaluation. But I love Haskell's purity and tend to treat lazy evaluation as an unhappy accident that only a few people (like John Hughes) know how to exploit.

You've observed a performance problem only because you've adapted an algorithm loaded with mutation, which Tony Hoare designed for imperative languages, and tried to translate into Haskell. In Haskell as in any other functional language the expensive operation is allocation. Try writing a merge sort and you'll find it's simple and performs very well.

How do you avoid making similar mistakes in the future? Have a look at Chris Okasaki's book Purely Functional Data Structures. Great book, and it will help you learn the 'functional way of doing things' without giving up performance.

于 2008-12-20T04:19:54.947 回答
22

快速排序在 Haskell 中没有那么快有一个非常具体的原因。这是一个神一般的算法示例,它在其工作方式中融入了出色的黑客技术——在这种情况下,我所说的黑客技术是真正的 Haskell 爱好者认为不必要的危险和非数学的技术。最初的实现尽一切努力打破 Haskell 强加给自己的规则:真正的快速排序通过用新信息覆盖存储槽来工作。在 Haskell 中这样做是非常痛苦的,它发现对现有信息进行全新的复制要容易得多。

因此,尽管那个朴素的两行 Haskell 版本抓住了快速排序的一些本质(它进行了相同数量的键比较),但它并不是真正的快速排序。它缺少很大一部分进入它的天才,它充分利用了调整现有值状态的能力。因此,它会生成大量列表片段的中间副本。

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

于 2008-12-18T07:33:20.113 回答
13

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

于 2008-12-18T08:58:48.587 回答
8

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

不过我认为这是值得的,就像有些人认为值得学习 Lisp 一样,即使你永远不会真正将它用于任何事情。这是值得的,因为它让你成为一个更好的程序员——它让你以不同的方式思考。我认为 Haskell 也有类似的效果。

于 2008-12-19T22:33:54.830 回答
4

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

要了解编译器面临的问题... 将 Haskell 程序翻译成 C,使其尽可能接近原始程序,然后尝试优化该 C 代码(不要以 C 方式从头开始重写)

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

于 2008-12-18T08:29:55.977 回答