2009-11-04 13 views
31

Ich schrieb eine Reihe von Code in Haskell, um einen Index eines Textes zu erstellen. Die Top-Funktion sieht wie folgt aus:Eine Haskell-Funktion des Typs: IO String-> String

index :: String -> [(String, [Integer])] 
index a = [...] 

Jetzt habe ich diese Funktion einen String aus einer Datei lesen geben möchten:

index readFile "input.txt" 

Welche wird nicht funktionieren, weil readfile vom Typ FilePath ist -> IO String .

nicht Typ 'String' gegen abgeleiteten Typ 'IO String' Könnte übereinstimmen

erwartet

Ich sehe den Fehler, aber ich kann keine Funktion mit type:

IO String -> String 

Ich denke, der Schlüssel zum Erfolg liegt irgendwo unter einigen Monaden, aber ich konnte keinen Weg finden, mein Problem zu lösen.

+3

Werfen Sie einen Blick hier für eine gute Monade Tutorial: http://blog.sigfpe.com/2006/ 08/you-könnte-haben-erfunden-monads-and.html –

+1

Andere gute Ressourcen finden Sie hier in SO. Sehen Sie sich einfach den Abschnitt Verwandte Themen an, rechts unten auf Ihrem Bildschirm. –

Antwort

37

Sie können einfach eine Funktion schreiben, die die Aktion readFile aufruft und das Ergebnis an Ihre Indexfunktion übergibt.

readAndIndex fileName = do 
    text <- readFile fileName 
    return $ index text 

jedoch verdirbt die IO Monade alles, was es verwendet, so dass diese Funktion hat den Typ:

readAndIndex :: FilePath -> IO [(String, [Integer])] 
+3

Es ist nur ein kleiner Satz: "Die IO-Monade vergiftet alles, was sie benutzt". Ich nahm an, dass dies der Fall war, aber es ist schön, es jetzt bestätigt zu sehen. Danke ^^ – drumfire

15

Nun, Sie können die IO Monade Teil von IO String nicht loswerden. Das bedeutet, dass Sie Ihre Funktion IO [(String, [Integer])] zurückgeben müssen.

Ich empfehle mehr über Monaden lernen, aber jetzt können Sie mit der liftM Funktion weg:

liftM index (readFile "input.txt") 

liftM hat diese Unterschrift:

liftM :: Monad m => (a -> b) -> m a -> m b 

Es dauert eine nicht-monadische Funktion und verwandelt es in eine monadische Funktion.

27

Es gibt einen sehr guten Grund, warum es keine solche Funktion.

Haskell hat den Begriff der funktionalen Reinheit. Dies bedeutet, dass eine Funktion immer dasselbe Ergebnis liefert, wenn sie mit denselben Parametern aufgerufen wird. Der only Ort, an dem IO zulässig ist, befindet sich in der IO-Monade.

Wurde eine Funktion *

index :: IO String -> String 

dann könnten wir plötzlich tun IO Aktionen überall durch den Aufruf, zum Beispiel:

index (launchMissiles >> deleteRoot >> return "PWNd!") 

Funktionelle Reinheit ist eine sehr nützliche Funktion, die wir don Ich möchte nicht verlieren, da es dem Compiler erlaubt, Funktionen viel freier neu zu ordnen und inline zu arbeiten, sie können zu verschiedenen Kernen gezündet werden, ohne die Semantik zu ändern, und es gibt den Programmierern auch ein Gefühl der Sicherheit, wenn Sie k Was nun eine Funktion von ihrem Typ kann und was nicht.

* Eigentlich ist eine solche Funktion. Es heißt unsafePerformIO und es heißt das für sehr, sehr gute Gründe. Verwenden Sie es nicht, es sei denn, Sie sind 100% sicher, was Sie tun!

+13

Ich würde gehen so weit zu sagen: "Verwenden Sie es nicht, wenn Sie 200% sicher sind, was Sie tun", oder noch einfacher, "nicht". –

+6

Ich würde sagen, die beste Verwendung für unsafePerformIO ist es, zu einem Prozess zu shell, die immer das gleiche zurückgeben sollte. dh eine Systemberechnung, die nicht standardmäßig von der Standardbibliothek unterstützt wird. – alternative

+4

Hinzufügen zu meinem alten Kommentar, den ich gerade beim Browsen in SO gefunden habe: Auch nützlich für FFI – alternative

8
fmap index $ readFile "input.txt" 

oder

readFile "input.txt" >>= return . index 

Möglicherweise möchten Sie in Monade suchen und functors

Verwandte Themen