0

如何制作自己的流式代码?我正在生成大约 1,000,000,000 对随机的战争套牌,我希望它们能够懒惰地流入 foldl',但我遇到了空间泄漏!这是代码的相关部分:

main = do
    games <- replicateM 1000000000 $ deal <$> sDeck --Would be a trillion, but Int only goes so high
    let res = experiment Ace games --experiment is a foldl'
    print res --res is tiny

当我使用 -O2 运行它时,它首先开始冻结我的计算机,然后程序死掉,计算机又恢复了活力(然后谷歌浏览器就有了它需要的资源来对我大喊大叫,因为我用光了它的所有资源。)

注意:我尝试了 unsafeInterleaveIO,但没有成功。

完整代码在: http: //lpaste.net/109977

4

2 回答 2

4

replicateM不做懒惰的流式传输。如果您需要从一元操作流式传输结果,您应该使用库,例如conduit​​ or pipes

您的示例代码可以编写为支持使用这样的管道进行流式传输:

import Data.Conduit
import qualified Data.Conduit.Combinators as C

main = do
    let games = C.replicateM 1000000 $ deal <$> sDeck
    res <- games $$ C.foldl step Ace
    -- where step is the function you want to fold with
    print res

Data.Conduit.Combinators模块来自conduit-combinators包。

作为一种快速而简单的解决方案,您可以实现replicateM使用惰性 IO 的流式处理版本。

import System.IO.Unsafe

lazyReplicateIO :: Integer -> IO a -> IO [a] --Using Integer so I can make a trillion copies
lazyReplicateIO 0 _   = return []
lazyReplicateIO n act = do
    a <- act
    rest <- unsafeInterleaveIO $ lazyReplicateIO (n-1) act
    return $ a : rest

但我建议使用适当的流媒体库。

于 2014-08-25T15:13:50.417 回答
2

等效的pipes解决方案是:

import Pipes
import qualified Pipes.Prelude as Pipes

-- Assuming the following types
action :: IO A
acc    :: S
step   :: S -> A -> S
done   :: S -> B

main = do
    b <- Pipes.fold step acc done (Pipes.replicateM 1000000 action)
    print (b :: B)
于 2014-08-25T15:59:37.327 回答