Ich versuche, mich mit einem Kernkonzept funktionaler Sprachen vertraut zu machen:
"Ein zentrales Konzept in funktionalen Sprachen ist, dass das Ergebnis einer Funktion durch ihre Eingabe und nur durch ihre Eingabe bestimmt wird. Es gibt keine Nebenwirkungen!"
Meine Frage ist, wenn eine Funktion Änderungen nur innerhalb ihrer lokalen Umgebung vornimmt und das Ergebnis zurückgibt, wie kann sie mit einer Datenbank oder einem Dateisystem interagieren? Würde das nicht per Definition auf eine globale Variable oder einen globalen Zustand zugreifen?
Welches ist das gebräuchlichste Muster, um dieses Problem zu umgehen oder zu lösen?
Das gebräuchlichste Muster für den Umgang mit Nebenwirkungen und Unreinheiten in funktionalen Sprachen ist:
Beispiele:
set!
var
Haskell schummelt ein wenig - seine Lösung ist, dass für Funktionen, die auf das Dateisystem oder die Datenbank zugreifen, der Status des gesamten Universums zu diesem Zeitpunkt , einschließlich des Status von Das Dateisystem / db wird an die Funktion übergeben. (1) Wenn Sie also den Status des gesamten Universums zu diesem Zeitpunkt replizieren können, können Sie die gleichen Ergebnisse erhalten zweimal von einer solchen Funktion. Natürlich können Sie nicht den Status des gesamten Universums zu diesem Zeitpunkt replizieren , und daher geben die Funktionen andere Werte zurück ...
Aber Haskells Lösung, IMHO, ist nicht die üblichste.
(1) Ich bin mir der Einzelheiten hier nicht sicher. Danke an CAMcCann für den Hinweis, dass diese Metapher überstrapaziert und vielleicht nicht so genau ist.
Nur weil eine funktionale Sprache funktional ist (vielleicht sogar völlig rein wie Haskell!), bedeutet das nicht, dass Programme, die in dieser Sprache geschrieben sind, rein sein müssen, wenn sie ausgeführt werden.
Haskells Ansatz, zum Beispiel im Umgang mit Nebenwirkungen, lässt sich einfach erklären: Lassen Sie das ganze Programm selbst rein sein (das bedeutet, dass Funktionen immer die gleichen Werte für die gleichen Argumente liefern und keine Nebeneffekte haben ), aber der Rückgabewert der Funktion main
sei eine Aktion, die ausgeführt werden kann.
Um dies mit Pseudocode zu erklären, hier ist ein Programm in einer Imperativ , nicht-funktionalen Sprache:
%Vor% Die obige Prozedur main
ist genau das: eine Reihe von Schritten, die beschreiben, wie eine Reihe von Aktionen ausgeführt wird.
Vergleichen Sie dies mit einer rein funktionalen Sprache wie Haskell. In funktionalen Sprachen ist alles ein Ausdruck, einschließlich der Hauptfunktion. Man kann also das Äquivalent des obigen Programms so lesen:
%Vor% main
ist also ein Ausdruck, der bei der Auswertung eine Aktion zurückgibt, die beschreibt, was zu tun ist, um das Programm auszuführen. Die eigentliche Ausführung dieser Aktion findet außerhalb der Programmierwelt statt. Und so funktioniert es wirklich; Folgendes ist ein aktuelles Haskell-Programm, das kompiliert und ausgeführt werden kann:
a >>= b
bedeutet in diesem Fall "die Aktion a
, gefolgt von dem Ergebnis von a
, das der Aktion b
" zugewiesen wurde, und das Ergebnis des Operators sind die kombinierten Aktionen a und b. Das obige Programm ist natürlich nicht idiomatisch Haskell; Man kann es wie folgt umschreiben (Entfernen der überflüssigen Variablen):
... oder mit syntaktischem Zucker und der Do-Notation:
%Vor%Alle oben genannten Programme sind nicht nur äquivalent, aber sie sind identisch soweit es den Compiler betrifft.
So können Dateien, Datenbanksysteme und Webserver als rein funktionale Programme geschrieben werden: indem Aktionswerte über das Programm zusammengeführt werden und schließlich in der Funktion main
enden. Dies gibt dem Programmierer eine enorme Kontrolle über das Programm und deshalb sind rein funktionale Programmiersprachen in manchen Situationen so ansprechend.
Die Verarbeitung einer Datenbank unterscheidet sich nicht von anderen Fällen der Eingabe / Ausgabe, z. B. print(17)
.
In eifrig bewerteten Sprachen, wie LISP und ML, verwendet der übliche Ansatz für eine effektive Programmierung nur Nebenwirkungen, wie in den meisten anderen Programmiersprachen.
In Haskell ist die Lösung für das IO-Problem die Verwendung von Monaden. Zum Beispiel, wenn Sie HDBC , ein Haskell überprüfen Datenbankbibliothek, Sie können viele Funktionen dort IO-Aktionen zurückgeben.
Einige Sprachen, wie Clean, verwenden Eindeutigkeits-Typen, um die gleiche Art von Sequenzialität zu erzwingen, die Haskell mit Monaden macht, aber diese Sprachen sind heutzutage schwieriger zu finden.
Tags und Links functional-programming side-effects