Kann * jede * Programmaufgabe ohne Status ausgedrückt werden?

13

Dies ist eine theoretische Frage, aber nach vielen Jahren des Programmierens in einer "normalen" imperativen Technik, die ich hauptsächlich mit C ++ verwende, habe ich diese andere Welt des funktionalen Programmierens entdeckt, auf die ich zufällig gestoßen bin, als ich zufällig JavaScript gelernt habe.

Ich habe mich gefragt, ob Sie ein komplettes staatsorientiertes Programm technisch durch eine andere Implementierung ersetzen könnten, die rein funktional und ohne Status ist.

Es ist eine faszinierende Idee und ich muss zugeben, dass die funktionale Programmierung eine Klarheit und Eleganz aufweist, die mich wirklich umgehauen hat.

Johnbakers
quelle
1
Eine relevante StackOverflow-Antwort: stackoverflow.com/questions/3722084/…
jfriend00
Ob es einen Zustand gibt, der von einem Zeitpunkt zum nächsten anhält, hängt nicht davon ab, welches Programmierparadigma Sie verwenden, sondern von dem Problem oder der Aufgabe, die Sie codieren. Wenn Sie zählen, wie oft auf eine Schaltfläche geklickt wurde, gibt es eindeutig einen Status zum Aufzeichnen dieses Zählers, und es spielt keine Rolle, welche Codierungstechnik Sie verwenden. Es muss einen Status geben, um den Zählerstand während des Vorgangs zu verfolgen. Daher kann diese bestimmte Aufgabe nicht ohne Status ausgeführt werden, unabhängig davon, wie Sie sie codieren.
jfriend00
6
Wenn Sie Zustand besprechen möchten; ein klarer Zustand ist erforderlich, wenn auch nur für das Programm selbst. Es hört sich so an, als würden Sie an einen veränderlichen oder unveränderlichen Zustand denken - Sie möchten vielleicht angeben, was Sie in der Frage meinen.
Billy ONeal
1
Das ist wie die Frage, ob alle Programme in echte Turing-Maschinen konvertiert werden können. Technisch gesehen ja, auch Programme, die aus einer Datenbank speichern und laden, jedoch wird es um ein Vielfaches schwieriger, dieses Verhalten in einer Turing-Maschine zu simulieren. Ebenso könnten Sie ein Programm haben, dessen Controllerseite in der MVC-Architektur entfernt ist und Sie alle Aufrufe ausführen, obwohl es wiederum schwieriger wird, mit Größen umzugehen (Sie werden im Wesentlichen der Controller, um das Programm zustandslos zu machen).
Neil

Antworten:

17

Kurze Antwort: ja. Laut Wikipedia wurde 1937 von Alan Turing die Äquivalenz der Lambda- Berechnung mit Turing-Maschinen als universelles Rechenmodell gezeigt. Das Rechenmodell einer Turing-Maschine ist das, woran Sie normalerweise denken, wenn Sie über imperative oder zustandsbehaftete Programmierung sprechen, und die Lambda-Berechnung ist eine mathematische Formalisierung der "reinen funktionalen Programmierung".

Es wird vermutet, dass jedes effektive Rechenmodell die gleichen Berechnungen durchführen kann wie eine Turing-Maschine und umgekehrt. Dies nennt man Church-Turing-These . Diese Vermutung kann jedoch aufgrund des mehr oder weniger intuitiven Begriffs "effektives Rechenmodell" nicht bewiesen werden (wird vielleicht in Zukunft jemand ein neues Modell erfinden?)

Doc Brown
quelle
2
Dasselbe Argument lässt sich umkehren, wenn man sagt, dass jede Berechnung einen (mehr oder weniger verborgenen) Zustand haben muss, da sie einer Reisemaschine entspricht. Ob es als außerhalb des Codes (mittels Variablen) oder innerhalb des Ablaufs (mittels stapelbasiertem Funktionsaufruf) dargestellt wird, ist immer "state".
Emilio Garavaglia
3
Lambda-Kalkül hat Zustand; Ihre Einschränkung ist, dass der Staat unveränderlich ist. Unveränderlicher Zustand ist immer noch Zustand. Die Parameter für Funktionen, einschließlich Lambdas, sind noch vorhanden. Vermutlich möchten Sie, dass eine Funktion bei unterschiedlichen Parametern ein unterschiedliches Verhalten aufweist.
Billy ONeal
@emilio Wenn Sie angeben, dass es für ein Problem (wie Sie beschreiben) eine äquivalente zustandsbasierte Lösung gibt, ist dies kein Beweis dafür, dass keine zustandslose Version dieser Lösung vorhanden ist.
Billy ONeal
2
@EmilioGaravaglia Sie beziehen sich dann auf den Zustand eines Lambda-Kalkül-Interpreters. Wenn in der Lambda-Rechnung argumentiert wird, besteht keine Notwendigkeit, über den Zustand zu argumentieren. Auch der Aspekt der "Veränderbarkeit" ist anders.
Wirrbel
1
@EmilioGaravglia: Der Status in der Imperativ-Programmierung ist jeweils die Speicherkonfiguration. Hier wird der Parameterraum durch alle möglichen Speicherwerte angegeben und der Status ist jeweils eine Konfiguration (Band der Turing-Maschine). Beim Schreiben eines Programms in die Lambda-Rechnung gibt es keine direkte Entität wie ein Speicherfeld. Die Programmausführung ist die Anwendung von Lambda-Transformationen. Zwischenschritte ähneln möglicherweise "state", sind jedoch nur äquivalente Ausdrücke desselben Werts. Während der Auswertung ändert sich nichts, die Ausdrücke werden nur umgeschrieben und in eine "einfachere" Form gebracht.
Wirrbel
14

In jedem dynamischen System ist der "Zustand" das, was Ihre Gegenwart von Ihrer Vergangenheit beeinflusst oder beeinflusst Zukunft beeinflusst (der Zeitpfeil ist kein mathematisches Problem, sondern nur eine physikalische Einschränkung).

Ob Sie sich an etwas "erinnern" müssen oder was davon abhängt, was Sie getan haben, Sie haben einen Zustand.

Ein System ohne Zustand ist nicht "dynamisch": Es ist nur eine kombinatorische Funktion. Das mag keinen Zustand haben, aber um unterschiedliche Ergebnisse zu erzielen, muss ein Zustand irgendwie geliefert werden.

Abhängig von dem Rechenmodell, auf das Sie sich beziehen, kann ein Zustand nun explizit (in Form einer Variablen) oder implizit (in Form von "Rücksprungadressen") dargestellt werden.

wenn Sie dies tun, geben fna(fnb(x))Sie fnb einen Zustand, der wiederum einen Zustand für fna erzeugt. Dies liegt an der Tatsache, dass es xexistiert, bevor fnb aufgerufen wird (es kommt also aus seiner eigenen "Vergangenheit").

Es geht nicht um "Staatsexistenz" oder "Staat existiert nicht". Es ist eine Angelegenheit von "Ich interessiere mich" oder "Ich nicht".

Emilio Garavaglia
quelle
0

Zustand bedeutet die Fähigkeit, auf einen gegenwärtigen Reiz in einer Weise zu reagieren, die von vergangenen Reizen abhängt und nicht nur auf dem gegenwärtigen Reiz basiert.

Rein funktionale Programme sind nur Funktionen. Für praktische Anwendungen gibt das rein funktionale Programm also ein Paar (old_state * present_stimulus) und ein Paar (new_state * present_response) ein. Ein externer, zustandsbehafteter "Looper" wird benötigt, um auf den nächsten Stimulus zu warten und den Zustand zu verbreiten.

Ein rein funktionales Programm hat keinen eigenen Status und kann nicht direkt für praktische Anwendungen verwendet werden.

Somit kann kein zustandsorientiertes Programm durch eine andere Implementierung ersetzt werden, die rein funktional und ohne Zustand ist.

Atsby
quelle
0

Sie können explizite veränderbare Zustände vermeiden, solange Sie nicht mit der Außenwelt interagieren müssen.

In JavaScript müssen Sie das Dom- oder das Window-Objekt ändern, damit Ihr Programm tatsächlich einen Effekt erzielt, der über die Auslastung der Prozessorzyklen hinausgeht. Diese APIs sind statusbehaftet. Aber ich nehme an, Sie könnten einen Wrapper erstellen, der die Dom- und Window-Objekte als Parameter an den JavaScript-Code übergibt und dann ein neues Dom / Window als Ausgabe erhält. Dies würde den JavaScript-Code vom veränderlichen Status isolieren.

Natürlich sind Sie immer noch unter Berufung auf Zustand, da die Browser - Fenster und DOM ist von Natur aus Stateful. Jede interaktive Anwendung ist von Natur aus statusbehaftet. Sie können den Code jedoch so strukturieren, dass der explizite Status minimiert wird.

Eine andere Frage ist, ob es eine gute Idee ist. Sogar Haskell, das von Natur aus eine reine funktionale Sprache ist, enthält die Monade 'state', mit der Sie einen veränderlichen Zustand simulieren können. Dies zeigt, dass ein expliziter veränderlicher Zustand manchmal wirklich ein wünschenswertes Muster ist.

JacquesB
quelle
0

Überlegen Sie, wie Sie eine "Zustandsmaschine" in einer Programmiersprache ohne Zustand implementieren würden.

Sie könnten es wahrscheinlich tatsächlich tun, aber Sie würden am Ende Funktionsnamen als Speicher verwenden. Am Ende sah der Gobblyday so aus:

if (sm.atBegining()) sm.start() else if (sm.done()) sm.stop() ) else sm.progress()
James Anderson
quelle