Was ist der Zweck der Staatsmonade?

8

Ich bin ein JavaScript-Entwickler auf dem Weg zu meinen Fähigkeiten in der funktionalen Programmierung. Ich bin kürzlich in eine Mauer gelaufen, als es um die Verwaltung des Staates ging. Bei der Suche nach einer Lösung habe ich in verschiedenen Artikeln und Videos über die State Monade gestempelt, aber es fällt mir wirklich schwer, sie zu verstehen. Ich frage mich, ob es ist, weil ich erwarte, dass es etwas ist, was es nicht ist.

Das Problem, das ich versuche zu lösen

In einem Webclient erhalte ich Ressourcen vom Backend. Um unnötigen Datenverkehr zu vermeiden, erstelle ich auf der Clientseite einen einfachen Cache, der die bereits abgerufenen Daten enthält. Der Cache ist mein Zustand. Ich möchte, dass einige meiner Module in der Lage sind, einen Verweis auf den Cache zu speichern und ihn nach seinem aktuellen Status abzufragen, ein Zustand, der möglicherweise von einem anderen Modul geändert wurde.

Das ist natürlich kein Problem in Javascript, da es möglich ist, den Status zu ändern, aber ich würde gerne mehr über funktionale Programmierung lernen und ich hoffte, dass die staatliche Monade mir helfen würde.

Was ich erwarten würde

Ich hatte angenommen, dass ich so etwas tun könnte:

%Vor%

Das funktioniert offensichtlich nicht. Der Staat ist immer 1.

Meine Frage

Sind meine Annahmen über die staatliche Monade falsch oder verwende ich sie einfach falsch?

Ich erkenne, dass ich das tun kann:

%Vor%

... und newState wird ein Zustand von 2. Aber hier sehe ich nicht wirklich die Verwendung der Zustands-Monade, da ich eine neue Instanz erstellen muss, damit sich der Wert ändert. Für mich scheint das das zu sein, was immer in der funktionalen Programmierung getan wird, wo Werte unveränderlich sind.

    
Ludwig Magnusson 29.01.2015, 20:46
quelle

4 Antworten

8

Der Zweck der Zustands-Monade ist es, den Übergang des Zustands zwischen Funktionen zu verbergen.

Nehmen wir ein Beispiel:

Die Methoden A und B müssen einen Zustand verwenden und mutieren, und B muss den Zustand verwenden, in dem A mutiert ist. In einer funktionalen Sprache mit unveränderlichen Daten ist dies unmöglich.

Was stattdessen getan wird, ist folgendes: Ein Anfangszustand wird zusammen mit den benötigten Argumenten an A übergeben, und A gibt ein Ergebnis und einen "modifizierten" Zustand zurück - wirklich ein neuer Wert, da das Original nicht geändert wurde . Dieser "neue" Zustand (und möglicherweise auch das Ergebnis) wird in B mit seinen erforderlichen Argumenten übergeben, und B gibt sein -Ergebnis und einen Zustand zurück, den er (möglicherweise) modifiziert hat.

Wenn man diesen Zustand explizit umgeht, ist dies ein PITA, also verbirgt die staatliche Monade dies unter seinen monadischen Abdeckungen und erlaubt Methoden, die auf den Zustand zugreifen müssen, um durch monadische Methoden get und set zu kommen.

Um die statusbehafteten Berechnungen A und B zu verwenden, kombinieren wir sie zu einer konglomeraten statusbehafteten Berechnung und geben diesem Konglomerat einen Anfangszustand (und Argumente), mit dem es laufen kann, und gibt einen endgültigen "modifizierten" Zustand und Ergebnis zurück Dinge durch A, B, und was auch immer es zusammengesetzt ist).

Nach dem, was du beschreibst, scheint mir, dass du nach etwas mehr suchst, das dem Akteurmodell der Nebenläufigkeit entspricht , wo Staat in einem Akteur gehandhabt wird und der Rest des Codes mit ihm dadurch in Verbindung tritt, die (eine nicht-veränderbare Version von) davon abruft oder ihm mitteilt, über Nachrichten geändert zu werden. In unveränderlichen Sprachen (wie Erlang) blockieren Akteure das Warten auf eine Nachricht, dann verarbeiten sie eine, wenn sie hereinkommt, und dann schleifen sie über (Schwanz-) Rekursion; Sie übergeben jeden modifizierten Zustand an den rekursiven Aufruf, und so wird der Status "modifiziert".

Wie Sie schon gesagt haben, ist es kein großes Problem, da Sie JavaScript verwenden.

    
paul 29.01.2015, 21:29
quelle
3

Es funktioniert tatsächlich wie Ihre zweite Beschreibung, wo ein neuer unveränderlicher Zustand zurückgegeben wird. Es ist nicht besonders nützlich, wenn Sie es so nennen. Nützlich ist es, wenn Sie eine Reihe von Funktionen haben, die Sie aufrufen möchten, wobei jeder den Status des vorherigen Schritts übernimmt und einen neuen Status und möglicherweise einen anderen Wert zurückgibt.

Wenn Sie es zu einer Monade machen, können Sie im Grunde nur eine Liste der auszuführenden Funktionsnamen angeben, anstatt das newState = f(initialState); newNewState = g(newState); finalState = h(newNewState); immer wieder zu wiederholen. Haskell hat eine eingebaute Notation namens Do-Notation, um genau dies zu tun. Wie Sie dies in JavaScript erreichen, hängt davon ab, welche Funktionsbibliothek Sie verwenden, aber in seiner einfachsten Form (ohne Bindung von Zwischenergebnissen) könnte es so aussehen wie finalState = do([f,g,h], initialState) .

Mit anderen Worten, die Zustands-Monade lässt die Unveränderlichkeit nicht magisch als Veränderlichkeit erscheinen, aber sie kann die Verfolgung von Zwischenzuständen unter bestimmten Umständen vereinfachen.

    
Karl Bielefeldt 29.01.2015 21:29
quelle
1

Ich versuche Ihre Frage aus der Perspektive eines Javascript-Entwicklers zu beantworten, weil ich glaube, dass dies die Ursache Ihres Problems ist. Vielleicht können Sie den Begriff Javascript in der Überschrift und in den Tags angeben.

Das Übertragen von Konzepten von Haskell auf Javascript ist grundsätzlich eine gute Sache, denn Haskell ist eine sehr ausgereifte, rein funktionale Sprache. Es kann jedoch, wie im Fall der Staatsmonade, zu Verwirrung führen.

Die vielleicht Monade zum Beispiel kann leicht verstanden werden, weil sie ein Problem behandelt, mit dem beide Sprachen konfrontiert sind: Berechnungen, die schief gehen könnten, indem sie keinen Wert zurückgeben ( null / undefined in Javascript). Maybe verhindert, dass Entwickler null im gesamten Code streuen.

Im Fall der staatlichen Monade ist die Situation ein wenig anders. In Haskell wird die Zustands-Monade benötigt, um Funktionen zu bilden, die sich einen veränderlichen Zustand teilen, ohne diesen Zustand passieren zu müssen. State ist eine oder mehrere Variablen, die nicht zu den Argumenten der beteiligten Funktionen gehören. In Javascript können Sie einfach Folgendes tun:

%Vor%

Dies ist die gewünschte Stateful-Berechnung und store muss nicht von Methode zu Methode weitergegeben werden. Auf den ersten Blick gibt es keinen Grund, die staatliche Monade in Javascript zu verwenden. Da store jedoch öffentlich zugänglich ist, mutieren push und pop den globalen Status. Mutation des globalen Staates ist eine schlechte Idee. Dieses Problem kann auf verschiedene Arten gelöst werden, von denen eine genau die Zustands-Monade ist.

Das folgende vereinfachte Beispiel implementiert einen Stapel als state monad:

%Vor%

Die verschachtelten Funktionsaufrufe könnten vermieden werden. Ich habe diese Funktion zur Vereinfachung weggelassen.

Es gibt kein Problem in Javascript, das nur mit der Zustands-Monade gelöst werden kann. Und es ist viel schwieriger, etwas so Generalisiertes zu verstehen wie die Staatsmonade, die ein scheinbar nicht existierendes Problem in der verwendeten Sprache löst. Seine Verwendung ist nur eine Frage der persönlichen Präferenz.

    
rand 20.11.2015 14:01
quelle
1

Staat ist überall präsent. In der Klasse könnte es der Wert seiner Eigenschaften sein. In Programmen könnte es der Wert von Variablen sein. In Sprachen wie Javascript und sogar Java, die Mutabilität erlauben, übergeben wir den Zustand als Argumente an die Mutationsfunktion. In Sprachen wie Haskell und Scala, die Mutation nicht mögen (als Nebenwirkungen oder unrein bezeichnet), wird der neue Staat (mit den Aktualisierungen) jedoch explizit zurückgegeben, der dann an seine Konsumenten weitergegeben wird . Um diesen expliziten Zustand zu verbergen, gibt Haskell (und Scala) dieses Konzept von State Monad. Ich habe einen Artikel dazu in Ссылка

geschrieben     
Lakshmi Rajagopalan 11.01.2017 08:55
quelle