gpt4 book ai didi

haskell - ST monad 的堆栈空间溢出

转载 作者:行者123 更新时间:2023-12-01 09:31:17 25 4
gpt4 key购买 nike

以下简短的 Haskell 程序旨在对文件中的项目列表进行计数。使用 foldl' 的版本工作正常,但使用 ST Monad 的版本给出堆栈空间溢出消息。显然这里存在某种空间泄漏,但我无法解决。真正有趣的部分是 ST monad 应该进行就地更新并且不应该让资源像这样增长,尽管这可能只与主内存有关而不与堆栈空间有关。有人可以解释这里发生了什么吗?

import Control.Monad
import Data.List
import Control.Monad.ST
import Data.STRef

--count items using foldl'
countFold :: Num a => [b] -> a
countFold = foldl' (\a _ -> a+1) 0

-- count items using the ST monad
-- derived fromt the sumST example on http://www.haskell.org/haskellwiki/Monad/ST
-- only using +1 instead of adding the values
countST :: Num a => [b] -> a
countST xs = runST $ do

n <- newSTRef 0

forM_ xs ( \_ -> modifySTRef n (+1) )

readSTRef n



main = do

mydata <- readFile "data_files/values_1000000.num"
let trainingdata = lines mydata

-- this works just fine
--(putStrLn (show (countFold trainingdata)))

-- This fails with the message:
-- Stack space overflow: current size 8388608 bytes.
-- Use `+RTS -Ksize -RTS' to increase it.
(putStrLn (show (countST trainingdata)))

更新:感谢您的回答和评论。我想我明白这里发生了什么。 modifySTRef' 是 4.6 版的新功能,它很好地解决了这个问题,并包含了某人提到的解释。我使用的是 Data.STRef 的 4.5 版,它在 Ubuntu 中似乎是标准版本,既不包含解释也不包含修改 STRef'。

查看 4.6 包版本和函数,不同之处在于它使用 seq 来确保函数 f 被严格应用(并存储在 x' 中):

modifySTRef :: STRef s a -> (a -> a) -> ST s ()
modifySTRef ref f = writeSTRef ref . f =<< readSTRef ref

modifySTRef' :: STRef s a -> (a -> a) -> ST s ()
modifySTRef' ref f = do
x <- readSTRef ref
let x' = f x
x' `seq` writeSTRef ref x'

所以解决它的另一种方法是将函数的代码复制到我自己程序空间中的一个新名称,并将 seq 应用于泄漏区域,这是我将来可能会使用的一个很好的通用技巧.感谢大家帮助我解决这个问题。

最佳答案

这是 a classic space leak .

modifySTRef 不会强制将其函数参数应用于状态的结果。事实上,您无法编写其参数函数来确保严格性。

请使用modifySTRef'

关于haskell - ST monad 的堆栈空间溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15065617/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com