如果我递归地定义斐波那契数列:
fibo_lazy_list = 0 : 1 : zipWith (+) fibo_lazy_list (tail fibo_lazy_list)
然后询问给定值之上的第一个元素,例如:print $ find (>100) fibo_lazy_list
我了解 Haskell 仅评估获得打印结果所需的元素。但是它们是否都保存在内存中直到打印?由于计算最后一个元素只需要列表的两个元素,Haskell 是释放最左边的元素还是列表在内存中不断增长?
最佳答案
这取决于。
对于真实世界的 Haskell 代码来说,这实际上是最棘手的事情之一:为了避免因持有不必要的数据而导致的内存泄漏,这本来应该是中间的,但结果实际上是对一些尚未的依赖 -未评估的惰性重击,因此不能被垃圾收集。
在您的示例中,fibo_lazy_list
的主要元素(顺便说一句,请使用 camelCase
,而不是在 Haskell 中使用 underscore_case
)只要 fibo_lazy_list
就不会被垃圾收集被仍然可以评估的东西引用。但是一旦超出范围,这是不可能的。所以如果你这样写
print $ let fibo_lazy_list = 0 : 1 : zipWith (+) fibo_lazy_list (tail fibo_lazy_list)
in find (>100) fibo_lazy_list
那么您可以非常确信未使用的元素将被垃圾收集,甚至可能在找到要打印的元素之前。但是如果
fibo_lazy_list
在顶层定义,并且是 CAF (如果类型不是多态的,它将是)fiboLazyList :: [Integer]
fiboLazyList = 0 : 1 : zipWith (+) fiboLazyList (tail fiboLazyList)
main :: IO ()
main = do
...
print $ find (>100) fiboLazyList
...
那么你应该更好地期望所有主要元素即使在 >100
之后仍保留在内存中。一个已被提取。编译器优化在这里可能会有所帮助,严格性注释也可以。但正如我所说,这对 Haskell 来说有点痛苦。
关于haskell - Haskell 在惰性求值期间会丢弃中间结果吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66018925/