2010-02-18 26 views
8

Ich versuche ein kleines Experiment in Haskell und frage mich, ob es möglich ist, Faulheit zu nutzen, um IO zu verarbeiten. Ich würde gerne eine Funktion schreiben, die einen String (eine Liste von Chars) nimmt und träge einen String erzeugt. Ich würde es dann mögen, wenn ich die Buchstaben von IO langsam füttern könnte, so würde jedes Zeichen so schnell wie möglich verarbeitet werden, und die Ausgabe würde erzeugt werden, sobald die benötigten Zeichen verfügbar wären. Ich bin mir jedoch nicht ganz sicher, ob/wie ich eine faule Liste von Zeichen aus der Eingabe innerhalb der IO-Monade erzeugen kann."Lazy IO" in Haskell?

+0

Bitte klar: Sie wollen eine Funktion, die einen String und "produziert" eine Zeichenkette --- "produziert" = "returns", "outputs to file handle", oder was? Und dann willst du es "lazily feed features from IO" --- was bedeutet das? – dave4420

Antwort

14

Regelmäßige String IO in Haskell ist faul. Dein Beispiel sollte also einfach funktionieren.

Hier ist ein Beispiel, mit dem ‚interact‘ Funktion, die eine Funktion zu einem faulen Strom von Zeichen gilt:

interact :: (String -> String) -> IO() 

Lasst uns den Buchstaben ‚e‘ aus dem Eingangsstrom herauszufiltern, träge (dh Lauf in konstantem Raum):

main = interact $ filter (/= 'e') 

Sie könnten getContents und putStr auch verwenden, wenn Sie mögen. Sie sind alle faul.

Laufen sie den Buchstaben ‚e‘ aus dem Wörterbuch zu filtern:

$ ghc -O2 --make A.hs 
$ ./A +RTS -s < /usr/share/dict/words 
... 
       2 MB total memory in use (0 MB lost due to fragmentation) 
... 

so sehen wir, dass es in einer konstanten 2M Fußabdruck lief.

+2

Sie können diesen Effekt auch in der Befehlszeile sehen. Führen Sie Don 'A' Programm in der Shell/Terminal/was auch immer Ihr Betriebssystem verwendet, und geben Sie Text direkt hinein. Unter der Annahme, dass die Zeile gepuffert ist, wird beim Drücken der Eingabetaste nach jeder Zeile der gefilterte Text sofort gedruckt, obwohl das Programm anscheinend nur einen "Aufruf" an "Filter" macht. – Nefrubyr

3
unsafeInterleaveIO :: IO a -> IO a 

unsafeInterleaveIO Allos IO Berechnung zu träge verschoben werden. Wenn ein Wert vom Typ IO a übergeben wird, wird IO nur ausgeführt, wenn der Wert a angefordert wird. Dies wird verwendet, um das Lesen von faulen Dateien zu implementieren, siehe System.IO.hGetContents.

Zum Beispiel ist main = getContents >>= return . map Data.Char.toUpper >>= putStr faul; Wenn Sie Zeichen an stdin übergeben, erhalten Sie Zeichen auf stdout.

(Dies ist die gleiche main = interact $ map Data.Char.toUpper wie das Schreiben, wie in der Antwort des dons.)

7

Die einfachste Methode faul IO tun beinhaltet Funktionen wie interact, readFile, hGetContents, und so, wie dons sagen; Es gibt eine ausführlichere Diskussion über diese in dem Buch Real World Haskell, das Sie nützlich finden könnten. Wenn Speicher mir dient, werden alle solche Funktionen schließlich unter Verwendung der unsafeInterleaveIO, die ephemient erwähnt, implementiert, so dass Sie auch Ihre eigenen Funktionen auf diese Weise erstellen können, wenn Sie möchten.

Auf der anderen Seite könnte es klug sein zu beachten, dass unsafeInterleaveIO ist genau das, was es auf der Zinn sagt: unsafe IO. Verwenden Sie es - oder Funktionen basierend darauf - breaks purity and referential transparency. Dies ermöglicht scheinbar reine Funktionen (dh, die keine IO Aktion zurückgeben), die Außenwelt zu beeinflussen, wenn sie ausgewertet werden, unterschiedliche Ergebnisse von denselben Argumenten und all diesen anderen unangenehmen Dingen zu erzeugen. In der Praxis verursachen die meisten vernünftigen Methoden unsafeInterleaveIO keine Probleme, und einfache Fehler führen normalerweise zu offensichtlichen und leicht zu diagnostizierenden Fehlern, aber Sie haben einige schöne Garantien verloren.

Es gibt natürlich Alternativen; Sie können verschiedene Bibliotheken auf Hackage finden, die eingeschränkte, safer lazy IO oder conceptually different approaches bieten. Da jedoch in der Praxis nur selten Probleme auftreten, sind die meisten Menschen geneigt, sich an die eingebauten, technisch unsicheren Funktionen zu halten.