为什么我的haskell程序太慢了?

时间:2015-05-11 01:58:57

标签: haskell

我尝试在ProjectEuler上解决问题443,https://projecteuler.net/problem=443

为了找到g的模式,我只是在Haskell中实现了g

g::Int->Int
g 4=13
g n=g (n-1)+n `gcd` g(n-1)

但计算列表t=[g i|i<-[4..100]]需要的时间超过1秒。 为什么会这样?即使没有记忆,每g(n)只需要O(n)。

编辑:当我在ideone中尝试此代码时,它很好,但在我的计算机中它不是。这是haskell版本的问题吗?我在Windows上使用版本ghc 7.8.3,而使用ghc 7.6。

2 个答案:

答案 0 :(得分:7)

  

每个g(n)只需要O(n)

不完全是。在你的递归案例中

g n=g (n-1)+n `gcd` g(n-1)

您正在呼叫g 两次。这意味着您实际上正在获得指数运行时间(O(2n))。

要确保g (n-1)在每个步骤中仅评估一次,请使用letwhere语句,以便您可以引用单个值 - 一次调用的结果 - 两次。

g :: Int -> Int
g 4 = 13
g n = let r = g (n-1)
      in r + n `gcd` r
  

当我在ideone中尝试使用此代码时,它很好,但在我的计算机中却没有。这是haskell版本的问题吗?

可能,虽然是一个优化级别参数问题。 Haskell的编译器可以在检测到表达式(如g (n-1))出现两次时优化诸如你的函数,但搜索这些函数代价高昂且需要启用。

答案 1 :(得分:5)

如果您将g的定义更改为:

g::Int->Int
g 4=13
g n=x+n `gcd` x
  where x = g (n-1)

然后,即使在ghcirunhaskell下,我也可以接受运行时间(而不是ghc -O2。)