繁体   English   中英

恒定空间中的单声道折叠

[英]Monadic Fold in Constant Space

如何在恒定空间中使用单子动作折叠懒惰列表? 我要解决的问题是聚合一个大文件,我相信出于性能考虑,我需要可变性。 我在ST中使用可变向量来实现一个实现,但是它使用了过多的内存。 以下是我正在尝试的示例。 我还对Conduit进行了简短的实验,但这似乎没有任何改善。

ST forM_:

import Control.Monad (forM_)
import Control.Monad.ST.Trans as STT
import Control.Monad.Identity as Identity

testST :: Int
testST = do
  Identity.runIdentity $ STT.runST $ do
    a <- STT.newSTRef 0
    forM_ [1..10000000] (\x -> do
        a' <- STT.readSTRef a
        STT.writeSTRef a (a' + x)
      )
    STT.readSTRef a

导管:

import Data.Conduit (($=),(=$),($$))
import qualified Data.Conduit as C
import qualified Data.Conduit.List as CL

testCL :: IO Int
testCL = CL.sourceList [1..10000000] $$ CL.foldM (\a x -> return (a + x)) 0

问题不在于褶皱,而在于褶皱主体。 这个程序分配了很多:

testST = runST $ do
    ref <- newSTRef 0
    forM_ [1..10000000] $ \x -> do
         val <- readSTRef ref
         writeSTRef ref (val + x)
    readSTRef ref

该程序的唯一区别在于writeSTRef行,它几乎不分配任何内容:

testST = runST $ do
    ref <- newSTRef 0
    forM_ [1..10000000] $ \x -> do
        val <- readSTRef ref
        writeSTRef ref $! val + x
    readSTRef ref

这两段代码之间的区别很好地说明了正在发生的事情:在前一个代码中,您正在创建对深度嵌套的thunk的引用,该thunk具有10000000层+的应用程序; 而后者在每一步都压扁了重击。

顺便说一句,这个常见的陷阱是modifySTRef的文档中明确modifySTRef

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM