Inkonsistente Notation in Funktionen
Warum ist diese Funktion erlaubt:
-- function 1
myfunc :: String
myfunc = do
x <- (return True)
show x
und das ist nicht:
-- function 2
myfunc :: String
myfunc = do
x <- getLine
show x
Der Kompilierungsfehler:
Couldn't match type `[]' with `IO'
Expected type: IO Char
Actual type: String
Ich verstehe, warum Funktion 2 nicht funktionieren sollte, aber warum dann also Funktion 1 funktioniert?
und warum funktioniert das dann:
-- function 3
myfunc = do
x <- getLine
return (show x)
Ich IO Stringverstehe , dass es dann zurückkehrt , aber warum ist Funktion 1 auch nicht dazu gezwungen?
Antworten
In Funktion1 arbeitet der doBlock in myfuncder Listenmonade, weil Stringes wirklich gerecht ist [Char]. Da return Truedrin schafft einfach [True]. Wenn Sie das tun x <- return True, "extrahiert" es Trueaus [True]und bindet es an x. Die nächste Zeile show xwird Truein einen String konvertiert "True". Der Rückgabewert, den der Compilerwert erwartet, funktioniert einwandfrei.
Währenddessen arbeitet in Funktion2 der doBlock in myfunc auch an der Listenmonade (aus dem gleichen Grund, Stringweil es wirklich so ist [Char]), ruft aber auf, getLinewas nur in der IOMonade verfügbar ist . Es ist also nicht überraschend, dass dies fehlschlägt.
- BEARBEITEN 1
OP hat eine Funktion3 hinzugefügt
-- function 3
myfunc :: String
myfunc = do
x <- getLine
return (show x)
Nein, dies sollte aus demselben Grund nicht funktionieren . Funktion2 schlägt fehl.
- BEARBEITEN 2
OP hat Funktion3 aktualisiert , um einen Fehler beim Kopieren und Einfügen zu beheben.
-- function 3
myfunc = do
x <- getLine
return (show x)
Dies wird in den Kommentaren erwähnt, aber aus Gründen der Klarheit funktioniert dies, da GHC, wenn die Typinformationen nicht spezifiziert sind, die beste Schlussfolgerung zieht und nach dem Sehen feststellt getLine, dass es das ist, IO Stringwas sie liefert getLine.
Hinweis - Ich habe diese Antwort mit einem so beiläufigen Ton geschrieben, wie ich es schaffen konnte, ohne mich zu irren, mit der Absicht, sie für Anfänger zugänglich zu machen.
doBlöcke arbeiten im Kontext einer beliebigen Monad. Das Monadist in diesem Fall []. Die MonadInstanz für Listen basiert auf Listenverständnissen:
instance Monad [] where
return x = [x]
xs >>= f = [y | x <- xs, y <- f x]
Sie können die doNotation folgendermaßen entschärfen :
myfunc :: String
myfunc = do
x <- (return True)
show x
-- ==>
myfunc = [y | x <- return True, y <- show x]
-- ==>
myfunc = [y | x <- [True], y <- show x]
In einem Listenverständnis x <- [True]ist das wirklich genau das gleiche wie let x = True, weil Sie nur ein Element aus der Liste zeichnen . So
myfunc = [y | y <- show True]
Natürlich ist "die Liste aller ysolchen, die ydrin sind show True" gerecht show True.