非点免费风格要慢得多

时间:2015-10-04 17:38:44

标签: haskell memoization

我有以下经常引用的代码来计算Haskell中的第n个Fibonacci数:

fibonacci :: Int -> Integer
fibonacci = (map fib [0..] !!)
    where fib 0 = 0
          fib 1 = 1
          fib n = fibonacci (n-2) + fibonacci (n-1)  

使用此功能,我可以进行如下调用:

ghci> fibonacci 1000

并得到一个几乎即时的答案。

但是,如果我修改上述代码,使其不是无点样式,即

fibonacci :: Int -> Integer
fibonacci x = (map fib [0..] !!) x
    where fib 0 = 0
          fib 1 = 1
          fib n = fibonacci (n-2) + fibonacci (n-1) 

它慢得多。在某种程度上,如

之类的呼叫
ghci> fibonacci 1000

挂起。

我的理解是上面两段代码是等价的,但GHCi要求不同。有没有人对这种行为有解释?

2 个答案:

答案 0 :(得分:11)

要观察差异,你应该看看Core。我猜这可以归结为比较(大致)

let f = map fib [0..] in \x -> f !! x

\x -> let f = map fib [0..] in f !! x

后者将在每次调用时从头开始重新计算f。前者没有,为每次调用有效地缓存相同的f

在这种特定情况下,一旦启用优化,GHC就能够将第二个优化为第一个。

但请注意,GHC并不总是执行此转换,因为这并不总是优化。第一个使用的缓存永远保存在内存中。这可能会导致内存浪费,具体取决于手头的功能。

答案 1 :(得分:0)

我试图找到它但被击中了。我想我家里的电脑上有它。 我读到的是使用固定点的函数本质上更快。 使用定点还有其他原因。我在编写这个迭代的Fibonacci函数时遇到了一个。我想看看迭代版本将如何执行然后我意识到我没有现成的测量方法。我是Haskell新手。但这是一个迭代版本,供有人测试。 除非我在第一个函数之后使用了点,否则我无法定义它。 我无法进一步减少它。 [0,1]参数是固定的,不作为参数值提供。

Prelude> fib = last . flip take (iterate (\ls -> ls ++ [last ls + last (init ls)]) [0,1])
Prelude> fib 25

[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025]

相关问题