Pipes.Binary.decode - wozu dient StateT?

8

Ich versuche, einen grundlegenden Netzwerkserver mit Pipes und den darauf aufbauenden Bibliotheken zu schreiben. Der beabsichtigte Fluss wäre:

bekomme bytestring von socket - & gt; Dekodieren mit Binär - & gt; Server Logik geht hier - & gt; Antwort an Socket senden

Was ich dachte, wäre etwas wie:

%Vor%

pipes-binary hat eine decode und eine decodeMany , aber ich bin mir nicht sicher, ob ich den Unterschied verstehe, und ich weiß nicht, wie man decode benutzt. Warum verwendet decodeMany die Upstream-Pipe als Argument, anstatt sie mit >-> zu verketten? Und wie benutzt du decode , wofür ist StateT und wie soll meine Pipe Chain aussehen?

    
user3261399 01.02.2014, 21:16
quelle

2 Antworten

5

Das StateT (Producer a m r) m x idiom kommt von pipes-parse "Low-Level-Parser" . Dies bedeutet normalerweise, dass die Bibliothek draw und unDraw verwendet, um Werte von Producer abzuziehen und sie zurückzugeben, wenn sie nicht verwendet werden. Es ist ein wesentlicher Bestandteil der Analyse, wo Fehler auftreten können. Außerdem muss die Schicht StateT angeben, dass eine Leitung selektiv in statusbehafteter Weise entleert und neu befüllt wird.

%Vor%

Was bedeutet das für decode und decodeMany ? Wenn wir uns einige vereinfachte Typen dieser Funktionen anschauen

%Vor%

Wir sehen zuerst, dass decode ist drawing off genug ByteString Chunks von Producer ByteString Stateful, um zu versuchen, ein b zu analysieren. Da die Chunk-Grenze in ByteString s möglicherweise nicht mit einer Parse-Grenze übereinstimmt, ist es wichtig, dies in StateT zu tun, damit die verbleibenden Chunks unDraw -ed zurück in Producer werden können.

decodeMany baut auf decode auf und versucht wiederholt, decode b s von der Eingabe Producer zurückzugeben, die bei einem Fehler eine "Fortsetzung" Producer von übrig gebliebenem ByteString s zurückgibt.

Lange Rede, kurzer Sinn, da wir unDraw übrig gebliebene ByteString -Brocken brauchen, können wir diese Dinge zusammen zu einer Kette mit (>->) zusammenfassen. Wenn Sie das tun wollen, können Sie etwas wie decodeMany verwenden, um einen Producer zu transformieren und dann das Ergebnis zu verketten, aber Sie sollten die Fehlerfälle sorgfältig behandeln.

    
J. Abrahamson 01.02.2014, 22:46
quelle
3

Ich möchte J. Abrahamsons Antwort ergänzen, indem ich Ihre andere Frage beantworte, warum der Decoder kein Pipe ist.

Der Unterschied zwischen einem Pipe und einem Typ wie:

%Vor%

... und Funktion zwischen Producer s wie (ich nenne diese "Getter" s):

%Vor%

... ist, dass ein Pipe verwendet werden kann, um Producer s, Consumer s und andere Pipe s:

zu transformieren %Vor%

... während ein "Getter" nur Producer s transformieren kann. Einige Dinge können nicht richtig modelliert werden mit Pipe s und Reste sind eines dieser Dinge.

conduit gibt vor, Reste mit Conduit s zu modellieren (das conduit analog von Pipe s), aber es ist falsch. Ich habe ein einfaches Beispiel zusammengestellt, das zeigt warum. Zuerst implementieren Sie einfach eine peek Funktion für conduit :

%Vor%

Dies funktioniert wie erwartet für einfache Fälle wie folgt:

%Vor%

Dies wird das erste Element der Quelle zweimal zurückgeben:

%Vor%

... aber wenn Sie eine Conduit upstream von Sink erstellen, gehen alle Reste, die die Senke zurückdrückt, unwiderruflich verloren:

%Vor%

Nun gibt der zweite peek falsch 2 zurück:

%Vor%

Beachten Sie auch, dass pipes-parse gerade eine neue Hauptversion veröffentlicht hat, die die API vereinfacht und ein umfangreiches Tutorial hinzufügt, das Sie lesen können hier .

Diese neue API propagiert Reste weiter stromaufwärts korrekt. Hier ist das analoge Beispiel für pipes :

%Vor%

Auch wenn das erste peek ebenfalls auf die ersten 10 Werte beschränkt ist, zieht es den ersten Wert korrekt zurück und stellt ihn dem zweiten peek zur Verfügung:

%Vor%

Der Grund, warum pipes-parse "in Producer s denkt", liegt konzeptionell daran, dass ansonsten das Konzept der Reste nicht klar definiert ist. Wenn Sie nicht klar definieren, was Ihre Quelle ist, können Sie nicht deutlich artikulieren, wo die Restewerte liegen sollten. Deshalb eignen sich Pipe s und Consumer s nicht gut für Aufgaben, die Reste benötigen.

    
Gabriel Gonzalez 02.02.2014 11:51
quelle

Tags und Links