无法强制尾递归严格

时间:2019-05-27 02:03:20

标签: haskell memory-leaks 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

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

1 个答案:

答案 0 :(得分:6)

force x = x `seq` x

那没用。 seq并不意味着“立即评估”。意思是“在返回正确的事物的结果之前先评估左边的事物”。当它们相同时,它什么也不做,并且您的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函数。在这种情况下,它的语义是“在返回评估结果之前,先评估列表中的所有元素”。如果您使用其force函数代替自己的函数,则原始代码将可以正常工作,因为loop的第一行确实会评估列表的开头。