Haskell: Einfügen jede Zeile aus einer Datei in eine Liste
Frage
Ich arbeite derzeit mit Haskell an Project und habe mir einige Ärger gehabt. Ich soll in einer Liste in einer "Dictionary.txt" -Datei in eine Liste lesen und einfügen, aber ich kann dies nicht tun. Ich habe diesen Code:
main = do
let list = []
loadNums "dictionary.txt" list
loadNums location list = do
inh <- openFile location ReadMode
mainloop inh list
hClose inh
mainloop inh list = do
ineof <- hIsEOF inh
if ineof
then return ()
else do
inpStr <- hGetLine inh
inpStr:list
mainloop inh list
Es soll jede Zeile erhalten (ich weiß, dass es jede Zeile erhält, da das Ersetzen der "INPSTR: Liste" durch ein "putstrln Inpstr" korrekt funktioniert, alle Zeilen anzeigen) und sie in eine Liste einfügen, aber ich erhalte den folgenden Fehler :
Couldn't match expected type `IO' against inferred type `[]'
Wahrscheinlich, weil die HGetline keine Zeichenfolge, sondern eine IO -Zeichenfolge ist, die ich nicht mit der Handlung habe, um eine ordnungsgemäße Zeichenfolge zu erhalten, die ich in meine Liste einfügen kann. Ich habe keine Ahnung, wie dies gelöst werden könnte oder wie genau das Problem ist, aber wenn jemand eine Vorstellung davon hat, wie man jede Zeile in einer Datei in eine Liste richtig einbringt, würde ich es schätzen.
Danke im Voraus!
Lösung
In der Zeile, in der der Fehler auftritt, erwartet Haskell "io a", aber Sie geben ihm eine []. Die Dinge zu vereinfachen, auf einem Do -Block auf dem IO -Monad, jede Zeile ist entweder:
- Etwas, das einen Wert des "io a" -Typs zurückgibt; Der Wert des "A" -Typs darin wird verworfen (so dass das "a" oft "()")
- A <- Ausdruck, der dasselbe tut, aber anstatt den Wert des "a" -Typs zu verwerfen, gibt ihm den Namen links vom <-
- A let, was nichts anderes tut, als einem Wert einen Namen zu geben
In diesem Block gibt die "HGetline -Inh" eine "IO -String" zurück, und die darin enthaltene Zeichenfolge wird extrahiert und den Namen inpstr gegeben. Die nächste Zeile, da es weder ein Let noch ein <-einen Typ "io a" haben sollte, was dies nicht der Fall ist (wodurch der Compiler-Fehler verursacht wird). Was Sie stattdessen tun können, da Sie bereits die Zeichenfolge haben, ist ein Let:
let list' = inpStr:list
Dadurch wird eine neue Liste erstellt, die aus der Zeichenfolge besteht, gefolgt von der ursprünglichen Liste, und gibt ihr den Namen "Liste" ".
Ändern Sie die folgende Zeile, um "Liste" anstelle von "Liste" zu verwenden (so die neue Liste übergeben). Diese Zeile ruft (rekursiv) Mainloop auf, die eine weitere Zeile lesen, sich selbst nennen und so weiter. Nach dem Lesen der gesamten Datei wird etwas mit dem Typ "io ()" zurückgegeben. Dieses "io ()" wird in den Block bei Loadnums zurückgegeben. Herzlichen Glückwunsch, Sie haben gerade eine Liste mit den Zeilen erstellt, die aus der Datei in umgekehrter Reihenfolge gelesen wurden (da Sie sich an den Kopf der Liste angemeldet haben) und dann nichts damit getan haben.
Wenn Sie etwas damit anfangen möchten, ändern Sie die "return () in" Rückgabeliste ". Die Rückgabe erzeugt einen Wert des Typs "IO [String], wobei die Liste darin (Rückgabe ist nichts anderes als das Einkapselung des Werts), den Sie an Loadnums mit der <-Syntax extrahieren können.
Der Rest bleibt dem Leser als Übung.
Andere Tipps
Wenn dies nicht für Hausaufgaben oder so ist, gibt es keinen Grund, so viel Mühe zu verwenden. Wiederverwendung ist faul!
getLines = liftM lines . readFile
main = do
list <- getLines "dictionary.txt"
mapM_ putStrLn list
Aber wenn Sie noch Haskell zu lernen scheinen, ist es für Sie wichtig zu verstehen, was Cesarb geschrieben hat.