haskell - Haskell 在惰性求值期间会丢弃中间结果吗?

标签 haskell lazy-evaluation lazy-sequences

如果我递归地定义斐波那契数列:

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/

相关文章:

multithreading - 并行过滤惰性序列

list - 在 Haskell 中合并 3 个列表

json - 在 Haskell 中构建 JSON 类型

haskell - 如何在 Haskell 中使用 GNU 黄金链接器而不是 ld 链接

haskell - 非严格和惰性有何不同?

scala - 延迟 val 解析的优雅方式

haskell - 是否可以将呈现的案例优化为一个循环?

python - Numpy 选择懒版本

scala - Scala 可变集合的 View 有什么惰性?

clojure - 在 REPL 中实现 Clojure 惰性序列(字符串)