【发布时间】:2015-08-06 05:38:27
【问题描述】:
如果想假装 Haskell 是严格的并且我有一个算法不利用惰性(例如它不使用无限列表),如果我只使用会出现什么问题严格的数据类型并注释我使用的任何函数,使其参数严格?是否会有性能损失,如果有,有多糟糕;会出现更严重的问题吗?我知道盲目地让每个函数和数据类型变得严格是肮脏、毫无意义和丑陋的,我不打算在实践中这样做,但我只想了解如果这样做,Haskell 默认会变得严格吗?
其次,如果我淡化这种偏执,只对数据结构进行严格的处理:只有在我使用某种形式的累加时,我才需要担心由惰性实现引起的空间泄漏 ?换句话说,假设该算法在严格的语言中不会出现空间泄漏。还假设我在 Haskell 中使用 only 严格的数据结构实现了它,但是小心地使用 seq 来评估在递归中传递的任何变量,或者使用内部小心执行该操作的函数(如折叠'),我会避免任何空间泄漏吗?请记住,我假设在严格的语言中,相同的算法不会导致空间泄漏。所以这是一个关于lazy和strict的实现区别的问题。
我问第二个问题的原因是因为除了试图通过使用惰性数据结构或脊椎严格的数据结构来利用惰性的情况之外,我到目前为止看到的所有空间泄漏示例,只涉及在累加器中开发的 thunk,因为它不是递归调用的函数,在将自身应用于累加器之前没有评估累加器。我知道,如果一个人想利用懒惰,那么必须格外小心,但在默认情况下严格的语言中也需要这种谨慎。
谢谢。
【问题讨论】:
-
所有这些问题都很好:这取决于 - 是的,我知道这很蹩脚 - 但你真的应该更具体一点 - 让我们看看你对 `seq 的评论' 一会儿:这只会评估为 WHNF 所以也许你不会获得太多,...... - 对不起,但这个问题只是为了给出一个很好的答案 - 至少在我看来:( - 这就是为什么我会忽略这些东西,直到你遇到麻烦 - 然后看看是什么导致它并采取相应的行动 - btw:这就是为什么你不像在严格的语言中那样使用累加器;)
-
我知道它会评估为 WHNF,但我只使用严格的数据结构。我知道过早优化不好,但我想从理论的角度知道,我是否会面临任何问题。
-
您最终可能会使用更少的内存(例如,避免 thunk 积累,如您的示例所示)或更多的内存,例如
foldl' (+) 0 $ map (+1) [1..1000]在严格的实现中分配 2000 个列表单元(当然,除非进行了一些优化)。在未优化的惰性实现中,我们仍然有 2000 个单元,但它们可以更早地被垃圾收集,因此在任何时候只有固定时间在内存中。 -
@chi,是的,根据情况,懒惰确实会带来优势。但是,假设我的算法不依赖于惰性,那么对我的所有函数和数据类型添加严格性并没有什么坏处?如果 Haskell 默认是严格的,我的情况并不比我差?
-
如果一切都很严格,我相信您应该获得与 F# 或 Ocaml 等严格语言相当的性能。我猜它会比这些慢一些,因为运行时没有针对这种情况进行优化。但是运行时完全不同,而且相当复杂——我不深入了解它,所以我无法确定。
标签: haskell lazy-evaluation strict