懒惰评估 - 空间泄漏

Kev*_*ith 1 haskell

使用Haskell进行功能性思考提供了以下用于计算Float列表平均值的代码.

mean :: [Float] -> Float
mean [] = 0
mean xs = sum xs / fromIntegral (length xs)
Run Code Online (Sandbox Code Playgroud)

Richard Bird教授评论道:

现在我们已经准备好了解真正意义上的错误:它有空间泄漏.评估mean [1..1000]将导致列表在求和后被扩展并保留在内存中,因为有一个指向它的第二个指针,即计算其长度.

如果我没有理解这段文字,他说,如果没有指针xs的长度计算,那么xs内存可能已经被释放计算的sum

我的困惑是 - 如果xs已经在内存中,那么length功能是不是只使用已经被占用的相同内存?

我不明白这里的空间泄漏.

Fré*_*ont 7

sum函数不需要将整个列表保存在内存中; 它可以一次查看一个元素然后忘记它移动到下一个元素.

因为默认情况下Haskell有懒惰的评估,如果你有一个创建列表的函数,sum可以使用它而不需要整个列表在内存中(每次生成函数生成一个新元素时,它会被sum释放时使用) .

完全相同的事情发生在length.

另一方面,该mean函数将列表提供给sumlength.因此,在评估期间sum,我们需要将列表保留在内存中,以便length稍后进行处理.

[更新]要明确,列表最终将被垃圾收集.问题是它比需要的时间长.在这种简单的情况下,它不是问题,但是在无限流上运行的更复杂的函数中,这很可能导致内存泄漏.