2011-05-05 14 views
15

在具有懒惰语义的纯功能性的语言(如Haskell中),计算的结果被memoized使得具有相同的输入的功能的进一步的评估不重新计算的值而是直接从memoized值的高速缓存得到它。像Haskell这样的函数式语言中,memoized值的生命期是多少?

我想知道如果这些memoized值获得在某个时间点回收?

  1. 如果是这样,则意味着memoized值必须在稍后的时间重新计算,并记忆化的好处是不那么退出恕我直言。
  2. 如果没有,那么OK,这是聪明的缓存的一切......但它意味着一个程序 - 如果运行时间足够长一段 - 将 总是消耗越来越多的内存?

想象一个程序执行密集的数值分析:例如,要查找的使用二分法算法几千几百数学函数列表的根。

每次节目评估与特定的实数的数学函数,结果将被memoized。但是,只有一个非常小的概率 是完全一样的实数将在算法中再次出现,导致内存泄露(或至少,真的不好的用法)。

我的想法是,也许memoized的值只是“作用域”的程序中的某些东西(例如对当前的延续,调用堆栈等),但我无法找到有关该主题的实用内容。

我承认我没有在Haskell编译执行深深的看了(懒惰?),但请,可能有人向我解释,在实践中是如何工作的?


编辑:好吧,我明白了从最初的几个回答我的错误:纯语义意味着引用透明而这又并不意味着自动记忆化,而只是保证会有它没有问题。

我认为网上的一些文章会误导这件事,因为从初学者的角度来看,参考透明属性看起来很酷,因为它允许隐式记忆。

+0

查看http://stackoverflow.com/questions/3951012/when-is-memoization-automatic-in-ghc-haskell – 2011-05-22 16:11:36

回答

19

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

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

在这里,记忆化只是一个通话中做fib,而如果你在顶层

fib n = fibs !! n 

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

离开fibs然后备忘录列表会一直保留,直到垃圾收集器可以确定没有其他方法可以从程序的任何部分到达fibs

+0

+1对于这个暗示性的例子 - 虽然我敢打赌,在这种情况下*实际上*编译器会看到fibs并不需要是一个本地值,并将其提升到最高层。 – Ingo 2011-05-05 13:45:55

+2

@Ingo:我的印象是,编译器_并没有让一个lambda外的任何东西浮动,正是因为这会对内存使用产生重大影响,但我可能是错的。 – hammar 2011-05-05 13:57:16

+0

@ngo:似乎有一个优化称为_full懒惰_这是做到这一点,但我不确定它是否适用于这种情况。 – hammar 2011-05-05 14:19:58

4

我的想法是,也许memoized值只是“作用域”的程序中的东西(例如对当前的延续,调用堆栈等)。),但我无法找到关于这个问题的实际情况。

这是正确的。特别是,当你看到这样:

fun x y = let 
    a = ..... 
    b = .... 
    c = .... 
in .... 

或等效的where子句中,值A,B和C可能没有被计算到实际使用(或者也可以马上计算,因为严格分析仪可以坡口说无论如何,这些值将被评估)。但是,当这些值取决于当前函数参数(这里是x和y)时,运行时很可能不会记住x和y以及由此产生的a,b和c的每个组合。

还要注意,在纯语言中,根本不记得这些值也是可以的 - 这只有在内存比CPU时间便宜时才实用。

所以你的问题的答案是:没有这样的事情在Haskell中间结果的生命。所有人可以说的是,评估的价值将在需要时在那里。

相关问题