Warum müssen wir State Monad verwenden, statt den Status direkt zu übergeben?

9

Kann jemand ein einfaches Beispiel zeigen, in dem die Zustandsmonade besser sein kann als den Zustand direkt zu übergeben?

%Vor%

vs

%Vor%     
ais 17.07.2015, 12:22
quelle

3 Antworten

14

Das Übergeben von Staaten ist oft mühsam, fehleranfällig und behindert das Refactoring. Versuchen Sie beispielsweise, einen Binärbaum oder einen Rosenbaum in der folgenden Reihenfolge zu kennzeichnen:

%Vor%

Hier musste ich die Zustände manuell in der richtigen Reihenfolge beschriften, die richtigen Zustände weitergeben und sicherstellen, dass sowohl die Beschriftungen als auch die Kindknoten in der richtigen Reihenfolge im Ergebnis sind (beachten Sie, dass foldr naiv verwendet wird) oder foldl für die Kindknoten hätte leicht zu einem falschen Verhalten führen können.)

Wenn ich versuche, den Code in die Vorbestellung zu ändern, muss ich auch Änderungen vornehmen, die leicht falsch sind:

%Vor%

Beispiele:

%Vor%

Vergleichen Sie die State-Monad-Lösung:

%Vor%

Dieser Code ist nicht nur prägnanter und einfacher zu schreiben, auch die Logik, die zur Kennzeichnung vor oder nach der Bestellung führt, ist viel transparenter.

PS: Bonusanwendungsstil:

%Vor%     
András Kovács 17.07.2015, 14:00
quelle
5

Als Beispiel für meine Kommentar oben, können Sie Code mit der State Monade wie

schreiben %Vor%

Beachten Sie, dass Sie bei Verwendung zusätzlicher Operatoren von Control.Lens auch incrCnt und logMsg als

schreiben können %Vor%

Dies ist ein weiterer Vorteil der Verwendung von State in Kombination mit der lens -Bibliothek, aber zum Vergleich verwende ich sie nicht in diesem Beispiel. Um den obigen äquivalenten Code mit nur passendem Argument zu schreiben, würde es eher wie

aussehen %Vor%

An dieser Stelle ist es nicht so schlimm, aber sobald wir zum nächsten Schritt kommen, werden Sie sehen, wo die Code-Duplizierung wirklich ankommt:

%Vor%

Ein weiterer Vorteil, dies in einer Monad -Instanz zu erreichen, ist, dass Sie die volle Leistung von Control.Monad und Control.Applicative damit nutzen können:

%Vor%

Dies ermöglicht viel mehr Flexibilität bei der Verarbeitung von Werten, die zur Laufzeit im Vergleich zu statischen Werten berechnet werden.

Der Unterschied zwischen der manuellen Statusübergabe und der Verwendung der State -Monade ist einfach, dass die State -Monade eine Abstraktion über den manuellen Prozess ist. Es passt auch zu mehreren anderen allgemeineren Abstraktionen, wie Monad , Applicative , Functor und einige andere. Wenn Sie auch den Transformer StateT verwenden, können Sie diese Operationen mit anderen Monaden zusammenstellen, z. B. IO . Kannst du das alles ohne State und StateT machen? Natürlich kannst du das, und es gibt niemanden, der dich davon abhält, aber der Punkt ist, dass State dieses Muster abstrahiert und dir Zugriff auf eine riesige Toolbox mit allgemeineren Werkzeugen gibt. Außerdem bewirkt eine kleine Änderung der oben genannten Typen, dass die gleichen Funktionen in mehreren Kontexten funktionieren:

%Vor%

Diese funktionieren jetzt mit App oder mit StateT MyState IO oder einem anderen Monad Stack mit einer MonadState Implementierung. Es macht es deutlich wiederverwendbarer als die einfache Argumentübergabe, was nur durch die Abstraktion StateT möglich ist.

    
bheklilr 17.07.2015 14:37
quelle
0

Nach meiner Erfahrung klickt der Punkt vieler Monads nicht wirklich, bis Sie zu größeren Beispielen kommen, also hier eine Beispielverwendung von State (gut, StateT ... IO ), um eine eingehende Anfrage an einen Webservice zu analysieren .

Das Muster ist, dass dieser Webservice mit einer Reihe von Optionen verschiedener Typen aufgerufen werden kann, obwohl alle außer einer der Optionen über anständige Standardwerte verfügen. Wenn ich eine eingehende JSON-Anfrage mit einem unbekannten Schlüsselwert erhalte, sollte ich mit einer entsprechenden Nachricht abbrechen. Ich benutze den Zustand, um zu verfolgen, was die aktuelle Konfiguration ist, und was der Rest der JSON-Anfrage ist, zusammen mit einer Reihe von Accessor-Methoden.

(Basierend auf dem aktuell in Produktion befindlichen Code, wobei sich die Namen von allem geändert haben und die Details dessen, was dieser Dienst tatsächlich tut, verdeckt)

%Vor%     
Daniel Martin 17.07.2015 14:18
quelle