无法在尾递归中强制严格
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
的第一行确实计算列表的开头。
我正在处理我的 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
的第一行确实计算列表的开头。