在像Haskell这样的函数式语言中,memoized值的生命周期是多少?

What is the lifetime of a memoized value in a functional language like Haskell?

在具有惰性语义的纯函数语言(如haskell)中,计算结果被记忆化,这样具有相同输入的函数的进一步评估就不会重新计算该值,而是直接从记忆化值的缓存中获取该值。

我想知道这些记忆值是否在某个时间点被回收?

  • 如果是这样,则意味着必须在以后重新计算memoized值,并且memoized的好处并不那么明显。
  • 如果不是,那么好吧,这是聪明的缓存一切…但这是否意味着程序——如果运行足够长的时间——将总是消耗越来越多的内存?
  • 想象一个程序执行密集的数值分析:例如,使用二分法算法查找数十万个数学函数的根。

    每次程序用一个特定的实数计算一个数学函数时,结果都会被记忆。但可能性很小在算法过程中会再次出现完全相同的实数,从而导致内存泄漏(或者至少是非常糟糕的使用)。

    我的想法是,记忆化的值可能只是简单地"限定"到程序中的某个内容(例如当前的延续、调用堆栈等),但我在这个主题上找不到实用的内容。

    我承认我没有深入研究haskell编译器实现(lazy?)但是,有人能给我解释一下它在实践中是如何工作的吗?

    编辑:好吧,我从最初的几个答案中理解了我的错误:纯粹的语义意味着引用的透明性,这反过来并不意味着自动记忆,但只是保证它不会有问题。

    我认为网络上的一些文章误导了这一点,因为从初学者的角度来看,参考透明性似乎很酷,因为它允许隐式记忆。


    Haskell不会自动记忆函数调用,因为这会很快消耗大量的内存。如果你自己做记忆,你可以选择记忆的功能范围。例如,假设您有这样定义的斐波那契函数:

    1
    2
    fib n = fibs !! n
        where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

    这里的memoization只在对fib的一次调用内完成,而如果您将fibs留在顶层

    1
    2
    3
    fib n = fibs !! n

    fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

    然后保存memoized列表,直到垃圾收集器确定没有更多方法从程序的任何部分到达fibs


    My idea is that maybe memoized values are simply"scoped" to something in the program (for example to the current continuation, call stack, etc.), but I was unable to find something practical on the subject.

    这是正确的。具体来说,当你看到如下情况时:

    1
    2
    3
    4
    5
    fun x y = let
        a = .....
        b = ....
        c = ....
    in ....

    或等效的WHERE子句,在实际使用之前,不可计算值a、b和c(或可立即计算,因为严格度分析仪可以保证稍后对值进行评估)。但是,当这些值依赖于当前函数参数(这里是x和y)时,运行时很可能不会记住x和y的每一个组合以及结果a、b和c。

    还要注意,在纯语言中,完全不记住值也是可以的——这只是在内存比CPU时间便宜的情况下才是可行的。

    所以,你的问题的答案是:没有这样的事情,中间人的一生会导致哈斯克尔。所有人都可以说,当需要时,评估值将在那里。