Verwenden Sie nicht unsafeInterleaveIO
oder irgendein lazy IO für diese Angelegenheit. Dies ist genau das Problem, dass iteratees erstellt wurden, um Folgendes zu beheben: Vermeidung von Lazy IO, was zu unvorhersehbarem Ressourcenmanagement führt. Der Trick besteht darin, niemals die Liste zu erstellen und es kontinuierlich mit Iteraten zu streamen, bis Sie fertig sind. Ich werde Beispiele aus meiner eigenen Bibliothek verwenden, pipes
, um dies zu demonstrieren.
Zunächst definieren:
import Control.Monad
import Control.Monad.Trans
import Control.Pipe
-- Demand only 'n' elements
take' :: (Monad m) => Int -> Pipe a a m()
take' n = replicateM_ n $ do
a <- await
yield a
-- Print all incoming elements
printer :: (Show a) => Consumer a IO r
printer = forever $ do
a <- await
lift $ print a
Nun wollen wir unseren Benutzer gemein sein und fordern sie die wirklich große Liste für uns produzieren:
prompt100 :: Producer Int IO()
prompt100 = replicateM_ 1000 $ do
lift $ putStrLn "Enter an integer: "
n <- lift readLn
yield n
Jetzt wollen wir es laufen:
>>> runPipe $ printer <+< take' 1 <+< prompt100
Enter an integer:
3<Enter>
3
Es fordert nur den Benutzer für eine ganze Zahl, da wir nur eine ganze Zahl fordern!
Wenn Sie prompt100
mit Ausgabe von getLargeList
ersetzen wollen, schreiben Sie einfach:
yourProducer :: Producer b IO()
yourProducer = do
xs <- lift getLargeList
mapM_ yield xs
... und dann laufen:
>>> runPipe $ printer <+< take' 1 <+< yourProducer
Dies wird lazily die Liste streamen und nie bauen die Liste im Speicher, alles ohne unsichere IO
Hacks. Um die Anzahl der von Ihnen angeforderten Elemente zu ändern, ändern Sie einfach den übergebenen Wert in take'
Weitere Beispiele finden Sie unter pipes
tutorial unter Control.Pipe.Tutorial
.
Um mehr darüber zu erfahren, warum Lazy IO Probleme verursacht, lesen Sie Olegs Original-Folien zum Thema, die Sie finden können here.Er erklärt die Probleme bei der Verwendung von Lazy IO sehr gut. Jedes Mal, wenn Sie gezwungen sind, faule IO zu verwenden, ist eine iteratee-Bibliothek das, was Sie wirklich wollen.
Vielleicht wird dies helfen. http://stackoverflow.com/questions/3270255/is-haskells-mapm-not-lazy –
Anton, ich habe dieses Thema gelesen, aber ich habe die Antwort nicht gefunden: Gibt es eine Alternative von mapM für Lazy-Berechnungen. –
@DmitryBespalov Nicht mit der gleichen Signatur. 'Monad' hat keine Abstraktion, um die Effekte auf später zu verschieben - und das ist es, was Sie tun müssen, damit' mapM' fauler wird. – Carl