Monadisches I/O
Next: Überladen in Gofer
Up: Ein- und Ausgabe
Previous: Continuations
Aus den Problemen, die viele Programmierer mit Dialogen hatten, wurde
das monadische I/O-Konzept entwickelt. [PJW93] Es basiert auf
eine Programmiermethode, die in geschickter Weise Daten implizit
weiterreicht, den Monaden. [Wad92][Wad90]
Eine Sequentialisierung kann in rein funktionalen Sprachen nur durch
Funktionakomposition adequat erreicht werden. Haben wir zwei I/O
Funktionen
und
, die nacheinander ausgeführt werden sollen,
so ist dieses am einfachsten zu erreichen, wenn
einen Wert hat den
als Eingabeargument zur Evaluierung benötigt. Wenn dieser Wert
von
dann in irgendeiner Weise noch die Umgebung (Filesystem etc)
darstellt, dann ist auch die referentielle Transparenz gewährleistet.
Diesem Gedanken liegt das monadische I/O zugrunde. Monaden stellen
zwei Operatoren zur Verfügung: bind ein Sequenzoperator,
der durch Komposition
realisiert wird, und unit einen Operator, der es erlaubt
komplexe Datentypen in eine Monade zusammenzupacken, die dann implizit
weitergereicht werden. Es kann also gut die für I/O benötigte Umgebung
(die World) in einer Monade enthalten sein und weitergereicht
werden.
Betrachten wir die beiden Aspekte des monadischen I/O getrennt:
- Sequenzialisierung
Wir benötigen zunächst einmal einen Operator, der uns aus einen
einfachen Datentyp ein für I/O Operationen monadisch verpackten
Datentyp generiert:
unitIO :: a -> IO a
Als zweiten Operator benötigen wir eine Funktion, die es uns erlaubt
Sequenzen von I/O Operationen mit dem monadisch verpackten Datentyp zu
definieren:
bindIO :: IO a -> (a -> IO b) -> IO b
Das erste Argument wird hier das Ergebnis einer I/O Operation oder aber
der unitIO-Funktion sein und das zweite Argument eine I/O Operation.
bindIO soll nun die Komposition eines Ausdrucks, der einen I/O
Seiteneffekt und als Ergebnistyp IO a hat mit einer weiteren I/O
Operation darstellen.
Mit diesen beiden Funktionen und vordefinierten I/O Funktionen kann nun
in natürlicher Weise eine Funktion definiert werden, die ein Wort aus
der Tastatur einliest:
wort :: IO String
wort = wortaux []
wortaux String -> IO String
wortaux w = getcIO `bindIO` \a ->
if ((a== eof) \/ (a==' ')) then
unitIO (reverse w)
else
(unitIO (a:w)) `bindIO` wortaux
- referentielle Transparenz
Bisher haben wir noch nicht betrachtet, in welcher Weise der Datentyp
IO a definiert ist, und wie die beiden Monadenfunktion auf ihm
operieren. Erst wenn wir jedoch genau wissen, wie die Umgebung in dieses
System integriert ist, können wir erkennen, dadie referentielle
Transparenz auch wieder durch enviroment passing für die I/O
Funktionen gewährleistet ist.
Der Typ IO a soll uns die Umgebung mit einem Datum des Typs a
verbinden, so dawir als versteckten Parameter auch die World in
den Funktionen haben:
type IO a = World -> IORes a
data IORes a = MkIORes a World
Der entscheidene Trick ist also, daIO a eine Funktion ist, die
für eine Umgebung ein Element von Typ a mit dieser Umgebung über
den Konstruktor MKIORes verknüpft. Die monadischen Funktionen werden
definiert als:
unitIO a w = MkIORes a w
bindIO m k w = case (m w) of
MkIORes a w' -> k a w'
Der Typ World ist ein
abstrakter Typ mit genau einer auf ihm definierten Funktion, der
Funktion ccall. Diese Funktion ist das einzige Sprachkonstrukt,
daHaskell zum Implementieren des monadischen I/O hinzugefügt wurde.
Es erlaubt eine beliebige C-Funktion aufzurufen, welche dann die
Kommunikation mit der Umgebung betreibt. Mit Hilfe dieser Funktion
werden die I/O-Funktionen definiert. Betrachten wir hierzu ein Beispiel:
putcIO a =\w ->
case a of
MkChar a# ->
case (ccall# putchar a# w) of
MkIORes# n# w' -> MkIORes () w'
Die monadischen I/O-Funktionen sind im derzeitigen Haskell-Standard
noch nicht eingebaut. Die meisten Haskell-Implementierungen bieten
monadisches I/O mitlerweile an. Monadisches I/O wird sicherlich in
Haskell 1.3 aufgenommen. Eine Vorabvorschlag hierzu ist schon auf dem
WWW erhältlich. (Adresse siehe weiter oben)
Next: Überladen in Gofer
Up: Ein- und Ausgabe
Previous: Continuations
Sven Eric Panitz
Mi., 01. Nov. 1995, 12:17:13