Problem mit unvollständigen Eingaben bei der Verwendung von Attoparsec
-
24-10-2019 - |
Frage
Ich konvertiere einen funktionierenden Haskell -Code, der Parsec verwendet, um stattdessen Attoparsec zu verwenden, in der Hoffnung, eine bessere Leistung zu erzielen. Ich habe die Änderungen und alles zusammengestellt, aber mein Parser funktioniert nicht richtig.
Ich analysiere eine Datei, die aus verschiedenen Datensatztypen pro Zeile besteht. Jede meiner individuellen Funktionen zum Parsen eines Datensatzes oder eines Kommentars funktioniert korrekt, aber wenn ich versuche, eine Funktion zu schreiben, um eine Folge von Datensätzen zu kompilieren, gibt der Parser immer ein Teilergebnis zurück, da er mehr Eingaben erwartet.
Dies sind die beiden Hauptvariationen, die ich ausprobiert habe. Beide haben das gleiche Problem.
items :: Parser [Item]
items = sepBy (comment <|> recordType1 <|> recordType2) endOfLine
Für diesen zweiten habe ich die Rekord-/Kommentar-Parsers geändert, um die Zeichen am Ende der Line zu konsumieren.
items :: Parser [Item]
items = manyTill (comment <|> recordType1 <|> recordType2) endOfInput
Stimmt etwas mit meinem Ansatz aus? Gibt es eine andere Möglichkeit, das zu erreichen, was ich versuche?
Lösung
Ich bin schon einmal auf dieses Problem gestoßen und mein Verständnis ist, dass es durch die Art und Weise verursacht wird <|>
funktioniert in der Definition von sepBy
:
sepBy1 :: Alternative f => f a -> f s -> f [a]
sepBy1 p s = scan
where scan = liftA2 (:) p ((s *> scan) <|> pure [])
Dies wird nur zu bewegen pure []
einmal (s *> scan)
ist gescheitert, was nicht passieren wird, nur weil Sie sich am Ende der Eingabe befinden.
Meine Lösung war nur anzurufen feed
mit einem empty
Bytestring auf der Result
zurückgekehrt von parse
. Dies mag eine Art Hack sein, aber es scheint auch, wie attoparsec-iteratee
befasst sich mit dem Thema:
f k (EOF Nothing) = finalChunk $ feed (k S.empty) S.empty
Soweit ich das sagen kann, ist dies der einzige Grund, warum attoparsec-iteratee
Arbeitet hier und schlicht alt parse
nicht.
Andere Tipps
Wenn Sie einen Attoparsec -Parser schreiben, der vor dem Ausfall so viel Eingabe wie möglich verbraucht, müssen Sie die teilweise Ergebnis fortgesetzt, wenn Sie das Ende Ihrer Eingabe erreicht haben.
Sie geben ziemlich wenig Informationen, weshalb ich es für schwierig ist, Ihnen gute Hilfe zu leisten. Es gibt jedoch ein paar Kommentare, die ich geben möchte:
- Vielleicht merkt der Parser nicht, dass die Eingabe erledigt ist und es hängt, entweder eine EOL zu bekommen oder einen anderen Datensatz zu erhalten. Daher fragt es nach einem Teilergebnis. Versuchen Sie, es dem Äquivalent von EOL in der Hoffnung zu füttern, dass es es zwingt.
- Ich kann mich nicht an den Code erinnern, aber die Verwendung der alternativen Instanz könnte sich für die Parsen -Leistung beeinträchtigen. Wenn dies der Fall ist, möchten Sie möglicherweise den Kommentar und den Aufzeichnung von Aufzeichnung.
- Ich benutze Müsli für eine Menge binäres Parsen und das ist auch extrem schnell. Attoparsec scheint jedoch als Text-Parser besser zu sein. Sie sollten die Option auf jeden Fall berücksichtigen.
- Eine weitere Option ist die Verwendung von ITeratee-basierten IOs länger. John Lato hat im neuesten Monad -Leser einen hervorragenden Artikel über ITeratees gemacht (ich glaube, ich glaube). Die Zeilenbedingung ist die Iteratees zu signalisieren. Achten Sie jedoch darauf, dass die Iteratee -Typen ziemlich entmutigend sind und sich einige Zeit benötigen.