Wie wird die readMaybe-Funktion in IO richtig verwendet?

7

Ich habe vor etwa vier Monaten mit dem Programmieren in Haskell angefangen und jetzt bin ich an den Punkt gekommen, wo ich mich mit dem IO-System von Haskell beschäftigen muss. Ich habe bereits viele IO-Aktionen durchgeführt und hatte keine Probleme, die ich selbst nicht lösen konnte, aber dieses Mal googelte ich fast zwei Stunden lang ohne Erfolg, um Informationen über die Funktion readMaybe zu erhalten. Also habe ich das folgende Problem zu lösen und ich habe bereits viele verschiedene Ansätze versucht, um es zu lösen, aber die ganze Zeit bekomme ich die gleiche Fehlermeldung von meinem Compiler:

%Vor%

Ich verstehe, was der Compiler mir sagen will, aber ich habe keine Ahnung, wie ich dieses Problem lösen soll. Ich habe bereits versucht, eine Klassenbeschränkung hinzuzufügen, aber ohne Erfolg. Also hier ist mein sehr kleines und einfaches Programm, das nur zählt, wie viele gültige Zahlen der Benutzer eingegeben hat. Das Programm soll beendet werden, wenn der Benutzer eine leere Zeile eingibt. Dies ist nur eine Hilfsfunktion, die ich später für mein Projekt verwenden möchte.

%Vor%

Leider konnte ich nicht viele Informationen über die Funktion readMaybe herausfinden. Das einzige, was ich finden konnte, war in der Haskell-Bibliothek Text.Read:

%Vor%

Das sehr Seltsame für mich ist, dass ich bereits eine solche Funktion geschrieben habe, die die readMaybe-Funktion verwendet und es hat perfekt funktioniert ... Dieses Programm fragt den Benutzer nur nach einer Nummer und fragt weiter, solange der Benutzer eine gültige Nummer eingibt

%Vor%

Soweit ich sehen kann, gibt es keine Unterschiede zwischen der Verwendung der Funktion readMaybe in den beiden Programmen und deshalb funktioniert sie in der einen, aber nicht in der anderen:)

Ich wäre wirklich dankbar für Hinweise von dir !!

    
tom1991te 29.12.2013, 22:55
quelle

2 Antworten

13

Das hat nichts mit IO zu tun, also verstehen Sie vielleicht nicht, was der Compiler Ihnen zu sagen versucht. Es gibt eine Typvariable a in readMaybe 's Signatur; a muss eine Read Instanz haben, aber ansonsten kann es alles sein. Der Compiler sagt Ihnen, dass es keine Möglichkeit gibt zu bestimmen, was a sein soll.

In getLineInt haben Sie dieses Problem nicht, weil Sie das Ergebnis von readMaybe zurückgeben und die Typensignatur sagt, dass es Int sein sollte. In countNumbers verwenden Sie nicht das Ergebnis von readMaybe . Es gibt also keine Möglichkeit, den richtigen Typ zu ermitteln. Sie können dies beheben, indem Sie eine explizite Typ-Signatur hinzufügen (Ich habe Int ausgewählt, da Sie anscheinend Zahlen zählen):

%Vor%

Endlich ein Wort über do notation: es ist nur syntaktischer Zucker, du musst es nicht ständig benutzen. Anstelle von do return x können Sie einfach return x und statt

schreiben %Vor%

Sie können einfach

tun %Vor%

Das macht die Dinge lesbarer:

%Vor%     
raymonad 29.12.2013, 23:10
quelle
9

Warum passiert das?

In Ihrer zweiten Funktion ist klar, dass readMaybe line als String -> Maybe Int verwendet wird, da Typinferenz bemerkt, dass Sie return x und daher x ein Int verwenden müssen.

In Ihrer ersten Funktion verwenden Sie den Wert Maybe überhaupt nicht, Sie möchten nur überprüfen, ob read erfolgreich war. Da Sie jedoch den Typ (weder explizit noch implizit mit Typinferenz) angegeben haben, ist die Typvariable nicht eindeutig:

%Vor%

Es gibt eine einfache Lösung: Kommentieren Sie den Typ:

%Vor%

Dies ist übrigens genau das gleiche Verhalten, das Sie bei der Verwendung von read in ghci ohne einen Kontexttyp kennen:

%Vor%

Sobald Sie den Typ klar machen, ist alles in Ordnung:

%Vor%

Klartext machen

Nun, da wir gesehen haben, warum der Fehler passiert, machen wir dieses Programm viel einfacher. Zuerst verwenden wir eine benutzerdefinierte readMaybe :

%Vor%

Nun, wie zählt man Zahlen? Zahlen sind die Wörter, bei denen readMaybeInt nicht Nothing zurückgibt:

%Vor%

Wie berechnet man nun die Zahlen in der Standardeingabe? Wir nehmen einfach die Eingabe, bis eine Zeile vollständig leer ist, map countNumbers für alle diese Zeilen und dann sum :

%Vor%

Wenn Sie nicht an die Bind-Methoden gewöhnt sind, ist das im Grunde

%Vor%

Alles in allem erhalten wir die folgende knappe Lösung:

%Vor%

Jetzt gibt es nur noch eine Funktion, die in der IO-Monade arbeitet, und alle Funktionen sind grundsätzlich Anwendungen von Standardfunktionen. Beachten Sie, dass getContents das Handle für die Standardeingabe schließt. Wenn Sie verwenden möchten, verwenden Sie besser etwas wie

%Vor%

, die Zeilen extrahiert, bis eine Zeile mit delim gefunden wurde. Beachten Sie, dass Sie in diesem Fall lineNumberCount ändern müssen:

%Vor%     
Zeta 29.12.2013 23:08
quelle

Tags und Links