提高 Haskell 性能的简单技巧(针对 ProjectEuler 问题)?
提高 Haskell 性能的简单技巧(针对 ProjectEuler 问题)?
我刚开始学习编程,正在通过阅读和解决Project Euler的问题来学习Haskell。当然,最重要的是要改善这些问题的性能,通过使用更好的算法。然而,对我来说,显然还有其他简单易懂的方法可以提高性能。一个随意的搜索带来了这个问题和这个问题,它们提供了以下提示:
- 使用ghc标志-O2和-fllvm。</ li>
- 使用类型Int,而不是Integer,因为它是未装箱的(甚至使用Int64而不是Integer)。这需要输入函数,而不是让编译器即兴创作。
- 使用rem而不是mod进行除法测试。</ li>
- 使用Schwartzian变换在适当的时候。</ Li>
- 在递归函数中使用累加器(我相信这是一个尾部递归优化)。</ Li>
- 备忘录(?)</ Li>
(一个答案还提到了worker / wrapper变换,但这似乎相当先进。)
问题:</ strong>在Haskell中有哪些其他简单的优化可以在Project Euler样式的问题上提高性能?还有其他特定于Haskell(或函数式编程?)的想法或特性可以用于加速解决Project Euler问题的解决方案吗?反之,人们应该注意什么?有哪些常见但低效的事情需要避免?</ p>
一个简单的建议是使用 `hlint`,它是一个检查您的源代码并就语法方面提出改进建议的程序。这可能不会增加速度,因为很可能已经由编译器或惰性评估完成。但在某些情况下它可能会帮助编译器。此外,它将使您成为更好的 Haskell 程序员,因为您将学习更好的做事方式,并且可能更容易理解和分析您的程序。\n\n其中一些示例可以从 http://community.haskell.org/~ndm/darcs/hlint/hlint.htm 上找到,例如:\n\n
darcs-2.1.2\src\CommandLine.lhs:94:1: Error: Use concatMap Found: concat $ map escapeC s Why not: concatMap escapeC s
\n\n和\n\n
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
\n\n我认为在解决 Project Euler 问题时,您可以做出的最大改进是了解问题并消除不必要的计算。即使您不理解所有内容,您也可以进行一些小的修复,这将使您的程序运行速度加倍。假设您正在寻找小于 1,000,000 的素数,则当然可以执行 `filter isPrime [1..1000000]`。但是如果您思考一下,就可以意识到好吧,大于 2 的偶数都不是素数,因此您已经删除了(大约)一半的工作。代替使用 `filter isPrime [1..1000000]`,您可以使用 `[1,2] ++ filter isPrime [3,5..999999]`。