【发布时间】:2016-01-25 05:16:38
【问题描述】:
Haskell 缓存纯函数调用的结果,这是区分纯行为和不纯行为的众多原因之一。然而,这个函数应该在 O(n) 中运行,其中 n 是下面的50,运行速度非常慢:
lucas 1 = 1
lucas 2 = 3
lucas n = lucas (n-1) + lucas (n-2)
map (lucas) [1..50]
前 30 项左右一起计算不到一秒,然后 31 需要半秒左右,32 需要一整秒,33 需要几秒,34 需要 6 秒,35 需要 11 秒,36 需要 17秒...
为什么这个功能这么慢?如果 GHC 交互式运行时正在缓存结果,那么对 lucas 的每次调用应该只涉及对前两个缓存项的求和。一次加法运算可找到第 3 项,一次加法运算可找到第 4 项,一次加法运算可找到第 5 项,因此在考虑缓存的情况下,总共只有 48 次加法即可达到第 50 项。该函数不应该花费任何时间来找到至少前几千个术语,为什么性能如此糟糕?
我已经等待lucas 500 计算半个多小时了。
【问题讨论】:
-
没有缓存 - 至少不是你期望的那样 - 这将与任何其他语言的行为相同
-
行为不是O(n^2),而是O(2^n)。
-
@WillemVanOnsem 哈哈哈,我看我有点太乐观了
-
无论如何我提到的两个版本都应该在几秒钟内为您提供前 500 个数字(基本上是在屏幕上打印它们所需的时间);)
-
顺便说一句,您自信地说“Haskell 缓存纯函数调用的结果”。为什么?那里有我们可以纠正的来源吗?很多人似乎都有这种误解......
标签: algorithm haskell caching big-o time-complexity