【发布时间】:2022-01-04 04:35:56
【问题描述】:
在阅读了几个资料后,我想出了以下 memo 函数,用于在 Haskell 中使用“广义递归”进行记忆。但它不起作用。为什么?!
fib f 0 = 1
fib f 1 = 1
fib f n = fib f (n - 1) + fib f (n - 2)
memo f n = fList !! n
where fList = map (f (fList !!)) [0..]
没有记忆的递归运行
λ> fix fib 30
1346269
(1.65 secs, 962,135,992 bytes)
与“记忆化”版本所用的时间相同:
λ> memo fib 30
1346269
(1.62 secs, 962,141,192 bytes)
但是,以下工作:
fibMemoDirect n = fibList !! n
where fibList = map fib [0..]
fib 0 = 1
fib 1 = 1
fib n = fibList !! (n - 1) + fibList !! (n - 2)
λ> fibMemoDirect 30
1346269
(0.01 secs, 93,728 bytes)
考虑到两者都使用 CAF,为什么上面的 memo fib 的工作速度不如 fibMemoDirect?
来源:
- Haskell Wiki
- Edward Kmett 的Stackoverflow answer
【问题讨论】:
-
!!是O(n),与其他语言中的O(1)不同。不过我不确定这是唯一的问题。 -
@user1984,是的,它确实不是最理想的。但是
fibMemoDirect也使用!!并且工作速度快了约200 倍。 -
为了确保它们渐近地不同并且差异不仅仅是一些恒定的,我建议运行 (30 * 5) 和 (30 * 10) 的代码,看看时间是如何变化的。
-
fibMemoDirect 3000在 0.13 秒内完成。memo fib 3000永远不会完成。 -
您的 fib 函数是直接递归的,不使用它的
f参数。所以你也可以在没有fix的情况下运行它,你会在同一时间得到相同的结果。这就是为什么用memo替换fix没有区别。
标签: haskell memoization