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?

War es hilfreich?

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.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top