2012-07-14 64 views
8

我是通过阅读和处理Project Euler问题来编程和学习Haskell的新手。当然,为了提高这些问题的性能,可以做的最重要的事情就是使用更好的算法。但是,我很清楚,还有其他简单易行的方法来提高性能。长大this question粗略搜索,并且this question,这给了以下建议:Haskell性能提升的简单提示(关于ProjectEuler问题)?

  • 使用GHC的标志-02和-fllvm。
  • 使用类型Int而不是Integer,因为它是非盒装的(甚至是Integer而不是Int64)。这需要输入函数,而不是让编译器即时决定。
  • 使用rem,not mod,进行分割测试。
  • 适当时使用Schwartzian transformations
  • 在递归函数中使用累加器(我相信是一个尾递归优化)。
  • 记忆化

(一个答案也提到了工人/包装改造,但似乎相当先进的。)

问号(?):可以在Haskell做什么其他简单的优化,以提高性能关于项目欧拉式问题?是否还有其他Haskell特定(或功能性编程特定?)的想法或功能可用于帮助加快Project Euler问题的解决方案?相反,应该注意什么?什么是一些常见但效率低下的事情需要避免?

回答

5

关于性能有一个fairly large section of the Haskell wiki

一个相当普遍的问题是严格性太低(或太多)(这在上面性能页面的General techniques部分中列出的部分涵盖)。太多的懒惰会导致大量的沉重积累,太严格会导致太多的评估。在编写尾递归函数(即带有累加器的函数)时,这些考虑尤为重要;而且,就此而言,根据函数的使用方式,即使使用最优严格标注,尾部递归函数在Haskell中的效率有时也低于等效的非尾部递归函数。

此外,通过this recent question作为证明,共享可以对性能有巨大的差异(在很多情况下,这也算是memoisation的一种形式)。

6

一个简单的建议是使用hlint这是一个程序,它检查你的源代码并提出改进语法方面的建议。这可能不会提高速度,因为它很可能已经由编译器或惰性评估完成。但它可能在某些情况下帮助编译器。更进一步,它会让你成为一个更好的Haskell程序员,因为你将学习更好的方法来做事情,并且可能更容易理解你的程序并分析它。从http://community.haskell.org/~ndm/darcs/hlint/hlint.htm采取诸如

例子:

darcs-2.1.2\src\CommandLine.lhs:94:1: Error: Use concatMap 
Found: 
    concat $ map escapeC s 
Why not: 
    concatMap escapeC s 

darcs-2.1.2\src\Darcs\Patch\Test.lhs:306:1: Error: Use a more efficient monadic variant 
Found: 
    mapM (delete_line (fn2fp f) line) old 
Why not: 
    mapM_ (delete_line (fn2fp f) line) old 

我觉得你可以在项目欧拉问题做了最大的增长是要了解这个问题,并删除不必要的计算。即使你不了解所有的东西,你可以做一些小的修复,这将使你的程序以两倍的速度运行。假设你正在寻找高达1.000.000的素数,那么你当然可以做filter isPrime [1..1000000]。但如果你想一点,那么你可以意识到这一点,甚至没有上面的数字是素数,你已经删除了(大约)一半的工作。而不是做[1,2] ++ filter isPrime [3,5..999999]

13

这里有一些很好的幻灯片由Johan Tibell,我经常提到:

Haskell Performance Patterns

+0

哇,很好的链接。谢谢。 – identity 2012-07-14 12:58:59

+1

同一作者的早期幻灯片http://blog.johantibell.com/2010/09/slides-from-my-high-performance-haskell.html更广泛;和http://johantibell.com/files/stanford-2011/performance.html是一个案例研究。有相当多的重叠,但它没有造成任何伤害。 – applicative 2012-07-14 17:46:22

3

项目欧拉主要是关于寻找聪明的算法解决的问题。一旦你有正确的算法,微优化几乎不是问题,因为即使是一个简单的或解释的(例如Python或Ruby)实现也应该在速度限制内运行。您需要的主要技巧是了解懒惰评估,以便避免thunk积累。