Unreine Sprachen unterscheiden sich im Prinzip nicht wirklich von den bekannteren imperativen Sprachen, zumal jetzt, da viele funktionale Tricks kopiert wurden. Was ist anders ist der Stil - wie Sie Probleme lösen.
Unabhängig davon, ob Sie Haskell als rein oder die IO-Monade als Verunreinigung betrachten, der Haskell-Stil ist eine extreme Form dieses Stils und es lohnt sich, ihn zu lernen.
Die Haskell IO-Monade leitet sich aus der mathematischen Theorie der (natürlich) Monaden ab. Für imperative Programmierer halte ich es jedoch für sinnvoller, rückwärts zu Monaden zu gelangen.
Phase eins - Eine reine funktionale Sprache kann als Ergebnis leicht einen großen Zeichenfolgenwert zurückgeben. Diese große Zeichenfolge kann der Quellcode eines zwingenden Programms sein, das auf rein funktionale Weise aus einigen anforderungsspezifischen Parametern abgeleitet wird. Sie können dann einen Compiler auf "höherer Ebene" erstellen, der Ihren Codegenerator ausführt und dann den generierten Code automatisch in den Compiler für imperative Sprachen einspeist.
Phase zwei - anstatt Text-Quellcode zu generieren, generieren Sie einen stark typisierten abstrakten Syntaxbaum. Ihr imperativsprachiger Compiler wird in Ihren "übergeordneten" Compiler aufgenommen und akzeptiert den AST direkt als Quellcode. Dies ist viel näher an dem, was Haskell tut.
Dies ist jedoch immer noch umständlich. Zum Beispiel haben Sie zwei verschiedene Arten von Funktionen - die, die während der Code-Generierungsphase ausgewertet werden, und die, die ausgeführt werden, wenn das generierte Programm ausgeführt wird. Es ist ein bisschen wie die Unterscheidung zwischen Funktionen und Vorlagen in C ++.
Machen Sie also für Phase 3 die beiden gleich - dieselbe Funktion mit derselben Syntax kann teilweise während der "Codegenerierung" ausgewertet oder vollständig ausgewertet oder überhaupt nicht ausgewertet werden. Verwerfen Sie außerdem alle Schleifenkonstruktions-AST-Knoten zugunsten der Rekursion. Verwerfen Sie die Idee von AST-Knoten tatsächlich als eine spezielle Art von Daten - haben Sie keine AST-Knoten mit "Literalwert", sondern nur Werte usw.
Dies ist so ziemlich das, was die E / A-Monade tut - der Bind-Operator ist eine Möglichkeit, "Aktionen" zu erstellen, um Programme zu bilden. Es ist nichts Besonderes - nur eine Funktion. Viele Ausdrücke und Funktionen können während der "Codegenerierung" ausgewertet werden, aber bei denen, die von E / A-Nebenwirkungen abhängen, muss die Auswertung bis zur Laufzeit verzögert werden - nicht nach einer speziellen Regel, sondern als natürliche Folge der Datenabhängigkeiten in Ausdrücke.
Monaden im Allgemeinen sind nur Verallgemeinerungen - sie haben die gleiche Schnittstelle, implementieren die abstrakten Operationen jedoch unterschiedlich. Statt eine Beschreibung des imperativen Codes zu erhalten, werden sie stattdessen zu etwas anderem ausgewertet. Dasselbe Interface bedeutet, dass Sie einige Dinge mit Monaden tun können, ohne sich darum zu kümmern, welche Monade sich als nützlich herausstellt.
Diese Beschreibung wird zweifellos puristische Köpfe explodieren lassen, aber für mich erklärt sie einige der wahren Gründe, warum Haskell interessant ist. Es verwischt die Grenze zwischen Programmierung und Metaprogrammierung und verwendet die Werkzeuge der funktionalen Programmierung, um die imperative Programmierung neu zu erfinden, ohne dass eine spezielle Syntax erforderlich ist.
Eine Kritik an C ++ - Vorlagen ist, dass es sich um eine Art kaputte rein funktionale Subsprache in einer imperativen Sprache handelt. Um dieselbe Grundfunktion zur Kompilierungszeit und nicht zur Laufzeit zu evaluieren, muss sie mit einem völlig anderen Stil erneut implementiert werden der Codierung. In Haskell muss die Verunreinigung in ihrem Typ als solche gekennzeichnet sein, aber genau dieselbe Funktion kann sowohl im Sinne einer Metaprogrammierung als auch im Sinne einer Laufzeit-Nicht-Metaprogrammierung in demselben Programm bewertet werden - es gibt keine harte Linie zwischen Programmierung und Metaprogrammierung.
Das heißt, es gibt einige Metaprogrammierungsfunktionen, die Standard Haskell nicht ausführen kann, da Typen (und möglicherweise ein paar andere Funktionen) keine erstklassigen Werte sind. Es gibt jedoch Sprachvarianten, die versuchen, dies zu beheben.
Viele Dinge, die ich über Haskell gesagt habe, können in unreinen funktionalen Sprachen angewendet werden - und manchmal sogar in imperativen Sprachen. Haskell ist anders, weil Sie keine andere Wahl haben, als diesen Ansatz zu wählen - er zwingt Sie im Grunde, diesen Arbeitsstil zu erlernen. Sie können "C in ML schreiben", aber Sie können nicht "C in Haskell schreiben" - zumindest nicht, ohne zu lernen, was unter der Haube vor sich geht.