无法在尾递归中强制严格

Unable to force strictness in tail recursion

我正在处理我的 Haskell 程序中的内存泄漏,我能够将它隔离为处理数组时非常基本的惰性问题。我明白那里发生了什么。计算数组的第一个元素,而其余元素产生消耗堆的延迟计算。不幸的是,我无法对整个数组计算强制严格。

我尝试了 seq、BangPatterns、($!) 的各种组合,但都没有成功。

import Control.Monad

force x = x `seq` x

loop :: [Int] -> IO ()
loop x = do
  when (head x `mod` 10000000 == 0) $ print x
  let x' = force $ map (+1) x
  loop x'

main = loop $ replicate 200 1

具有标准配置文件选项的配置文件没有提供比我已知更多的信息:

ghc -prof -fprof-auto-calls -rtsopts test.hs
./test +RTS -M300M -p -hc

这会在几秒钟内耗尽内存。

force x = x `seq` x

那没用。 seq 不代表 "evaluate this thing now";这意味着 "evaluate the left thing before returning the result of evaluating the right thing"。当它们相同时,它什么都不做,你的 force 等同于 id。试试这个:

import Control.DeepSeq
import Control.Monad

loop :: [Int] -> IO ()
loop x = do
  when (head x `mod` 10000000 == 0) $ print x
  let x' = map (+1) x
  loop $!! x'

main = loop $ replicate 200 1

计算 x'loop x' 之前的所有内容,这很有用。

或者,Control.DeepSeq 有一个有用的 force 函数。它在这种情况下的语义是 "evaluate all of the elements of your list before returning the result of evaluating any of it"。如果您使用它的 force 函数代替您自己的函数,那么您的原始代码会以其他方式工作,因为 loop 的第一行确实计算列表的开头。