Ich verwende Data.Serialize.Get
und versuche, den folgenden Kombinator zu definieren:
sollte wie die übergebene Get
-Aktion funktionieren, aber auch die ByteString
, die der Get
verbraucht hat, zurückgeben. Der Anwendungsfall ist, dass ich eine binäre Struktur habe, die ich sowohl analysieren als auch hashen muss, und ich kenne die Länge vor der Analyse nicht.
Dieser Kombinator erweist sich trotz seiner einfachen Semantik als überraschend schwierig zu implementieren.
Ohne ins Innere von Get
zu schauen, war mein Instinkt, diese Monstrosität zu benutzen:
Was Lookahead verwenden wird, einen Blick auf die verbleibenden Bytes vor und nach dem Ausführen der Aktion werfen, das Ergebnis der Aktion zurückgeben und dann die Länge konsumieren. Dies sollte keine Arbeit duplizieren, aber es scheitert manchmal mit:
%Vor%Ich muss also irgendwo etwas über Müsli verkennen.
Kann jemand sehen, was mit meiner Definition von getconsumed
falsch ist oder haben Sie eine bessere Idee, wie man es implementiert?
Bearbeiten: Dan Doel weist darauf hin, dass remaining
nur die verbleibende Länge eines gegebenen Chunks zurückgeben kann, was nicht sehr nützlich ist, wenn Sie eine Chunk-Grenze überschreiten. Ich bin nicht sicher, was der Punkt der Aktion ist, in diesem Fall, aber das erklärt, warum mein Code nicht funktionierte! Jetzt muss ich nur eine brauchbare Alternative finden.
Edit 2: Nachdem ich darüber nachgedacht habe, scheint die Tatsache, dass remaining
mir die Länge des aktuellen Chunks gibt, zu meinem Vorteil zu sein, wenn ich die Get
manuell mit einzelnen Chunks füttere ( remaining >>= getBytes
) in einer Schleife und verfolgen, was es isst, wie ich es tue. Ich habe es noch nicht geschafft, diesen Ansatz in Gang zu bringen, aber er scheint vielversprechender zu sein als der ursprüngliche Ansatz.
Edit 3: Wenn jemand neugierig ist, hier ist der Code von Edit 2 oben:
%Vor%Leider scheint es nach einer Weile immer noch an meiner Beispieleingabe mit:
zu scheitern %Vor%EDIT: Eine andere Lösung, die keine zusätzliche Berechnung durchführt!
%Vor% Eine Lösung besteht darin, lookAhead
zweimal aufzurufen. Das erste Mal stellt sicher, dass alle erforderlichen Chunks geladen sind, und das zweite Mal führt die Berechnung der tatsächlichen Länge aus (zusammen mit der Rückgabe der deserialisierten Daten).
Das Cereal-Paket speichert nicht genügend Informationen, um einfach das zu implementieren, was Sie wollen. Ich erwarte, dass Ihre Idee, Brocken zu verwenden, vielleicht funktioniert, oder vielleicht eine spezielle runGet
. Forking Cereal und die Verwendung der Interna ist wahrscheinlich der einfachste Weg.
Das Schreiben eigener Dateien kann funktionieren, das habe ich gemacht, als ich die Protokollpuffer-Bibliothek gemacht habe. Meine benutzerdefinierte Text.ProtocolBuffers.Get
Bibliothek implementiert genug Maschinen, um das zu tun, was Sie wollen:
Das ist klar, weil meine Bibliothek die Anzahl von byteRead verfolgt. Ansonsten ist die API Cereal sehr ähnlich.
Tags und Links haskell