haskell - 仅在某些情况下在 GHC 解释器中执行 : concat <some list> ! 时才会发生空间泄漏! n

标签 haskell ghc

我定义了我自己的 concat 版本, myConcat :

module Eh where

myConcat []          = []
myConcat ([]:os)     = myConcat os
myConcat ((x:xs):os) = x : myConcat (xs:os)

(!!!)  :: [a] -> Int -> a
xs     !!! n | n < 0 = error "negative index"
[]     !!! _         = error "index too large"
(x:_)  !!! 0         = x
(_:xs) !!! n         = xs !!! (n-1)

如果我这样做 myConcat <some huge list> !! n在 GHC 解释器中,它以 300MB/s 的速度窃取我的内存,我必须先杀死它,然后它才能召唤 OOM 杀手。注意这里我加载了Eh作为“解释”,我在加载它之前不编译它。

代码运行在 GHC 解释器空间泄漏?
myConcat(重复 [1,2,3,4])!! (10^8) 是的
连接(重复[1,2,3,4])! (10^8) 没有
myConcat(重复 [1,2,3,4])!!! (10^8) 没有
连接(重复[1,2,3,4])!!! (10^8) 没有

现在如果我编译 Eh ( ghc --make -O2 Eh.hs ),然后在解释器中加载它并重新运行这些测试,它们都没有空间泄漏。如果我编译每个测试用例而不是在解释器中运行它们,则相同。

这是怎么回事?

我正在运行 GHC 6.12.3。

最佳答案

这里的问题是严格性。 Haskell 中的评估是非严格的,因此通常仅在确实需要其结果时才执行计算。相反,会创建一个代表尚未执行的计算的所谓 thunk。

然而,在某些情况下,编译器可以检测到无论如何都需要计算结果,因此用实际计算代替了 thunk 的创建。

Haskell Wiki可能更好地解释了这一点。

修复您的 myConcat功能,您必须确保它不会通过手动强制严格评估来创建数百万个 thunk。一种(看起来不是很漂亮)的方法可能是:

myConcat []          = []
myConcat ([]:os)     = myConcat os
myConcat ((x:xs):os) = ((:) $! x) myConcat (xs:os)

关于haskell - 仅在某些情况下在 GHC 解释器中执行 : concat <some list> ! 时才会发生空间泄漏! n,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7707661/

相关文章:

haskell - 生成集合的子集。懒惰?

haskell - "cabal install happy"导致内存溢出。 (GHC 7.8.2)

haskell - "purely applicative Either"是否有标准名称或实现?

sql - 列表的内存中完全外部连接

haskell - 奇怪的 Haskell 行为 : misplaced error in record syntax?

haskell - 将返回类型限制为 Context

c - 为什么链接的二进制文件包含使用过的目标文件的文件名,如何删除它们?

haskell - cabal 安装错误为 LICENSE : openBinaryFile: does not exist (No such file or directory)

haskell - 重写作为 GHC : Is it really needed? 中的实用优化技术

haskell:在 haskell 平台 2013 2.0.0 中使用 writer monad 时,没有 (Monoid Int) 的实例