Как мне получить ленивый поток в складку?

Как создать собственный потоковый код? Я генерировал около 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, он сначала начинает зависать на моем компьютере, а затем программа умирает, и компьютер возвращается к жизни (а затем Google Chrome располагает ресурсами, которые ему нужны, чтобы кричать на меня за использование всех своих ресурсов.)

Примечание: я попытался unsafeInterleaveIO, и это не сработало.

Полный код по адресу: http://lpaste.net/109977

2 ответа

replicateM не делает ленивого потокового Если вам нужно передать результаты от монадических действий, вы должны использовать библиотеку, такую ​​как conduit или же 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

Но я рекомендую использовать правильную потоковую библиотеку.

Эквивалент 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)
Другие вопросы по тегам