Inkonsistente Notation in Funktionen

Oct 09 2020

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

12 SriKadimisetty Oct 09 2020 at 21:17

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.

9 dfeuer Oct 09 2020 at 21:59

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.