如何让懒惰的流媒体进入foldl'?

时间:2014-08-25 13:33:41

标签: haskell streaming lazy-loading space-leak lazy-io

如何制作自己的流媒体代码?我正在生成大约1,000,000,000个随机对战甲板,我希望它们可以懒得流入折叠式游戏机,但是我得到了空间泄漏!以下是相关的代码部分:

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

2 个答案:

答案 0 :(得分:4)

replicateM不会进行延迟流式传输。如果您需要从monadic操作传输结果,则应使用conduitpipes等库。

您的示例代码可以编写为支持带有这样的管道的流式传输:

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包。

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

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

但我建议使用正确的流媒体库。

答案 1 :(得分: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)