在具有惰性语义的纯函数式语言(例如Haskell)中,计算结果被记忆,因此对具有相同输入的函数的进一步求值不会重新计算该值,而是直接从memoized值的缓存中获取它。 / p>
我想知道这些记忆值是否会在某个时间点被回收?
想象一个程序执行密集的数值分析:例如,使用二分法算法找到数十万个数学函数列表的根。
每次程序评估具有特定实数的数学函数时,结果都将被记忆。但是概率很小 算法期间会再次出现完全相同的实数,导致内存泄漏(或者至少是非常糟糕的使用情况)。
我的想法是,或许memoized值只是简单地“限定”程序中的某些东西(例如当前的继续,调用堆栈等),但我无法找到关于该主题的实际内容。
我承认我没有深入研究Haskell编译器实现(懒惰?),但是,有人可以向我解释它在实践中是如何工作的吗?
编辑:好的,我从最初的几个答案中理解了我的错误:纯语义意味着参考透明度,这反过来并不意味着自动记忆,但只是保证它没有问题。
我认为网上的一些文章误导了这一点,因为从初学者的角度来看,参考透明度属性似乎很酷,因为它允许隐式记忆。
答案 0 :(得分:19)
Haskell 不自动记忆函数调用,正是因为这会快速消耗大量内存。如果你自己做了memoziation,你可以选择函数被记忆的范围。例如,假设你有像这样定义的斐波纳契函数:
fib n = fibs !! n
where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
此处的备忘录只能在一次致fib
的情况下完成,而如果您将fibs
留在最高级别
fib n = fibs !! n
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
然后保留记忆列表,直到垃圾收集器可以确定没有更多方法从程序的任何部分到达fibs
。
答案 1 :(得分:5)
我的想法是,或许memoized值只是简单地“限定”程序中的某些东西(例如当前的延续,调用堆栈等),但我无法找到关于该主题的实际内容。
这是对的。具体来说,当你看到类似的东西时:
fun x y = let
a = .....
b = ....
c = ....
in ....
或等效的where子句,在实际使用之前可能不会计算值a,b和c(或者可以立即计算它们,因为严格性分析器可以证明以后无论如何都要评估这些值)。但是当这些值依赖于当前函数参数(此处为x和y)时,运行时很可能不会记住x和y的每个组合以及结果a,b和c。
另请注意,在纯语言中,根本不记得这些值也是可以的 - 只有在内存比CPU时间便宜的情况下,这才是实用的。
所以问题的答案是:在Haskell中没有中间结果的生命周期。所有人都可以说,评估值将在需要时存在。