Daher könnte beispielsweise das Abfragen von Datenbanken oder das Schreiben von Dateien per Definition nicht in einem rein funktionalen Stil erfolgen. Das ist zum Beispiel einer der Gründe, warum wir Monaden brauchen.
Niemand "braucht" Monaden, das ist nur eine Möglichkeit, Dinge zu beschreiben. In der Tat ist es wahrscheinlich nicht einmal der beste Weg. Eine Form der Effekt-Typisierung , Eindeutigkeitstypen oder ein System, das auf einer vollständigen linearen Logik basiert, scheinen theoretisch überzeugender zu sein, sind jedoch radikalere Abweichungen von bekannten Typsystemen und komplizierter auszudrücken. Monadic IO, wie es in Haskell zu finden ist, ist ein Kompromiss zwischen Benutzerfreundlichkeit und Einfachheit, da es im Wesentlichen eine vollständig zwingende Programmierung auf eine Weise modelliert, die problemlos mit dem vorhandenen ML-Typ-System koexistiert, das bereits in der Sprache verwendet wird.
Die Frage ist - warum betrachten wir die STDOUT-Ausgabe als etwas Unreines? Ja, jeder Dateihandler ist riskant - wir können nie sicher sein, dass Daten immer geschrieben werden. Aber was ist mit STDOUT? Warum sollten wir es als etwas Unzuverlässiges betrachten? Ist es unzuverlässiger, dass die Bewertung selbst? Ich meine, wir können immer den Abzug betätigen und damit die Berechnung unterbrechen.
Es ist nicht und wir nicht. Die Eingabe in und Ausgabe von dem Programm als Ganzes kann einfach als Argumente angesehen werden und ergibt sich aus der Behandlung des gesamten Programms als eine große reine Funktion. Solange es dasselbe an stdout druckt, wenn Sie dasselbe von stdin füttern, ist es immer noch eine reine Funktion. Vor der Einführung der monadischen E / A verwendete Haskell ein Stream-basiertes E / A-System, das reine Lazy-Streams für die Eingabe und Ausgabe verwendete. Es hat es fallen lassen, weil es anscheinend schmerzhaft war, es zu benutzen, was Ihnen eine Vorstellung davon geben kann, warum Sie von so etwas noch nichts gehört haben. :]
Betrachten Sie die minimalistische esoterische Sprache Lazy K :
Lazy K ist eine durch Müll gesammelte, referenziell transparente funktionale Programmiersprache mit einem einfachen Stream-basierten E / A-System.
Was Lazy K von anderen solchen Sprachen unterscheidet, ist das fast völlige Fehlen anderer Merkmale. Es bietet beispielsweise kein integriertes polymorphes Hindley-Milner-System. Es wird nicht mit einer umfangreichen Standardbibliothek geliefert, die plattformunabhängige GUI-Programmierung und Bindungen an andere Sprachen unterstützt. Eine solche Bibliothek konnte auch nicht geschrieben werden, da Lazy K unter anderem keine Möglichkeit bietet, andere Funktionen als integrierte Funktionen zu definieren oder auf diese zu verweisen. Diese Unfähigkeit wird durch einen passenden Mangel an Unterstützung für Zahlen, Zeichenfolgen oder andere Datentypen ergänzt. Trotzdem ist Lazy K Turing-komplett.
(...)
Lazy K-Programme leben im gleichen zeitlosen platonischen Bereich wie mathematische Funktionen, was die Unlambda-Seite "den gesegneten Bereich des reinen untypisierten Lambda-Kalküls" nennt. So wie die Garbage Collection den Prozess der Speicherverwaltung vor dem Programmierer verbirgt, verbirgt die referenzielle Transparenz den Prozess der Auswertung. Die Tatsache, dass einige Berechnungen erforderlich sind, um ein Bild des Mandelbrot-Sets anzuzeigen oder um ein Lazy K-Programm "auszuführen", ist ein Implementierungsdetail. Das ist die Essenz der funktionalen Programmierung.
(...)
Wie gehe ich mit Ein- und Ausgaben in einer Sprache ohne Nebenwirkungen um? In gewissem Sinne sind Eingabe und Ausgabe keine Nebenwirkungen. es sind sozusagen Front- und Backeffekte. So ist es in Lazy K, wo ein Programm einfach als eine Funktion vom Raum möglicher Eingaben zum Raum möglicher Ausgaben behandelt wird.
Ich bezweifle, dass Sie eine rein funktionale Sprache finden werden!
Beachten Sie jedoch, dass das oben Gesagte nur gilt, wenn Sie im Wesentlichen die Eingabe und Ausgabe einer reinen Funktion übernehmen und sie in irgendeiner Weise "extern" mit stdin / stdout verbinden. Es gibt einen großen Unterschied zwischen dem und dem Zugriff auf die realen E / A-Grundelemente auf Systemebene. Die Implementierungsdetails des Lesens und Schreibens in die Ströme können Verunreinigungen verlieren, wenn sie nicht sorgfältig gekapselt werden.
Ich gehe davon aus, dass dies der Hauptgrund dafür ist, dass Sie dies nicht direkt in Haskell tun können - die vernünftigen Anwendungsfälle sind im Vergleich zur Verwendung von monadischen E / A schlank, und für letztere bietet der Zugriff auf die reale Sache viele Vorteile. Ich glaube, deshalb werden zum Beispiel die Befehlszeilenargumente an das Programm nicht einfach als Argumente übergeben main
, obwohl es intuitiv zu sein scheint.
Sie können jedoch eine minimale Version von so etwas in einem bestimmten Programm wiederherstellen - erfassen Sie einfach die Argumente als reine Werte und verwenden Sie dann die interact
Funktion für den Rest Ihres Programms.