你需要多长时间才能熟悉Haskell?
你需要多长时间才能熟悉Haskell?
我是一个还可以的C/C++程序员。我觉得Haskell非常有趣。但是对我来说,虽然写出干净的Haskell代码相对容易,因为它很好地模拟了数学(这是我非常熟悉的),但是在Haskell中编写快速且干净的代码却非常困难。
Haskell的快速排序的更快版本非常冗长和可怕,与幼稚但简短(两行)、干净和直观的实现根本没有相似之处。Haskell的长且可怕版本实际上仍然比简短和简单的C代码慢得多。
是因为当前的Haskell编译器太愚蠢,还是因为普通人(除了SJP)不可能编写快速的Haskell代码呢?
Haskell中快速排序不那么快的一个特定原因。它是一个算法,其内部嵌入了精妙的技巧,这种技巧被称为黑客技巧 - 我所说的黑客技巧是指Haskell忠实信徒认为非必要却危险和非数学的技术。最初的实现确实尽一切可能打破了Haskell强制执行的规则:真正的快速排序通过使用新信息覆盖存储槽来工作。在Haskell中这很痛苦,它更喜欢制作现有信息的完整新副本。
因此,尽管那个纯朴的两行Haskell版本捕捉了快速排序的本质(它执行了相同数量的关键字比较),但它并不是真正的快速排序。它缺失了其中很大一部分天才,即充分利用调整现有值状态的能力。因此,它对列表的大量中间副本进行了制作。
推测:Haskell编译器能否分析您的代码,运用与Hoare(快速排序的发明者)相同的推理方法,并发现它可以通过完全以有状态的方式重新实现来进行优化?可能可以。
你提出了两个不同的问题:学习和性能。
- 我用ML学习了递归、模式匹配、
map
、filter
和fold
,需要大约一个月的时间才能熟悉函数式编程。但这些知识很容易转换到Haskell中。 - 我用了两三年的时间才弄懂monad,但那是因为我读错了资料。现在有更好的教程了。但如果你刚开始学,最好先不要涉及monad。
- 我花了几个月的时间才能够灵活创建新的类型类,但使用已有的类型类很容易。
- 我仍然不确定我是否掌握了惰性求值。但我喜欢Haskell的纯度,并且认为惰性求值只是一种不愉快的偶然事件,只有像John Hughes这样的人才知道如何利用。
你注意到了性能问题,是因为你使用的算法具有变异,是Tony Hoare为命令式语言设计的。在任何一个函数式语言中(包括Haskell),昂贵的操作是分配内存。尝试编写一个归并排序,你会发现它简单并且表现良好。
如何避免将来犯类似的错误?看一看Chris Okasaki的书Purely Functional Data Structures。这是一本很棒的书,它将帮助你学习“函数式方法”而不失性能。