In Haskell werden die I/O Funktionen als ein Dialog zwischen Programm
und Betriebssystem modelliert. [O'D85] Dieser Dialog stellt
sich dar als eine unendliche Liste von Anfragen an das Betriebssystem [Request] auf Seite des Programms als Kommunikationspartner und eine
ebensolche Liste von Antwortmeldungen auf diese Anfragen des
Betriebssystems [Response].
Wir haben also die zwei Listen:
als Teile unseres Kommunikationsprozesses, wobei jeweils die
Antwort des Betriebssystems auf die Meldung
des Programms sein
sollen. Request und Response sind abstrakte Datentypen.
(zumindest für Request hätte man wohl eher Funktionen erwartet.)
Diese Listen erzwingen so schon die Sequenzialisierung der I/O Operationen.
Ein funktionaler Zusammenhang von den Anfragen auf die Antworten würde
der referentiellen Transparenz widersprechen. Der Trick ist nun den
Dialog gerade als Funktion von einer Liste von Antworten auf eine Liste
von Anfragen zu definieren:
Dialogue = [Response] -> [Request]
Dieses ist zunächst einmal recht konterintuitiv und trägt sehr zur
Verunsicherung von Programmierern bei. Es sei zB das -te Element des
Funktionswertes eines Dialogs die Meldung ReadFile datei; dann ist
das
-te Element des Arguments die Antwortmeldung des Betriebssystems
auf diesen Lesewunsch, also in der Regel der Art: Str dateiinhalt.
Eine Funktion main vom Typ Dialogue schreibt man nun in der
Art, dadie Funktion für die zu erwartenden Antwortpattern
spezifiziert wird und diese Pattern dann in weiteren Anfragen benutzt
werden. Unser anfängliches Beispielprogramm sähe also wie folgt aus:
>moin ~(~Success: ~(~(Str zahl) : ~(~Success:[]))) = > [AppendChan stdout "Geben Sie ein Zahl ein: ", > ReadChan stdin, > AppendChan stdout ("\n Das Quadrat von " > ++ (head (lines zahl)) > ++ " ist: " > ++ ausgabe > ++ "!\n" )] > where > ausgabe = int2string ((string2int (head (lines zahl)))^2)