Runhaskell表现异常

时间:2012-02-17 08:40:11

标签: haskell runhaskell

我正在尝试了解在runhaskell下运行程序时遇到的性能异常。

有问题的节目是:

isFactor n = (0 ==) . (mod n)
factors x = filter (isFactor x) [2..x]
main = putStrLn $ show $ sum $ factors 10000000

当我运行它时,需要1.18秒。

但是,如果我将isFactor重新定义为:

isFactor n f = (0 ==) (mod n f)

然后该程序需要17.7秒。

这是性能上的巨大差异,我希望这些程序是等效的。有人知道我在这里缺少什么吗?

注意:在GHC下编译时不会发生这种情况。

2 个答案:

答案 0 :(得分:9)

虽然功能应该相同,但它们的应用方式有所不同。通过第一个定义,isFactor完全应用于呼叫网站isFactor x。在第二个定义中,它不是,因为现在isFactor显式地接受了两个参数。

即使是最小的优化也足以让GHC看到它并为两者创建相同的代码,但是如果使用-O0 -ddump-simpl进行编译,则可以确定在没有优化的情况下,这会产生影响(至少与ghc- 7.2.1,YMMV与其他版本)。

使用第一个isFactor,GHC创建一个单独的函数,作为谓词传递给“GHC.List.Filter”,并调用内联mod 10000000(==)。对于第二个定义,相反的是,isFactor中的大多数调用都是对类函数的let-bound引用,并且不在isFactor的多个调用之间共享。因此,有很多字典开销是完全没必要的。

这几乎不是问题,因为即使是默认的编译器设置也会对它进行优化,但是runhaskell显然甚至没有这么做。即便如此,我偶尔会将代码结构化为someFun x y = \z ->,因为我知道someFun将被部分应用,这是保持调用之间共享的唯一方法(即GHC的优化器不够聪明)。 / p>

答案 1 :(得分:5)

据我了解,runhaskell几乎没有优化。它旨在快速加载和运行代码。如果它进行了更多优化,则代码开始运行需要更长时间。当然,在这种情况下,代码运行速度更快。

据我了解,如果代码的编译版本存在,那么runhaskell将使用它。因此,如果性能对您很重要,请确保首先打开优化进行编译。 (我想您甚至可以将开关传递给runhaskell以启用优化 - 您必须查看文档...)