2017-10-19 4 views
2

Ich benutze (Missbrauch) Parser, um einige String-Transformation, z. normalizeWS :: Parser String entfernt doppeltes Leerzeichen und normalizeCase bildet spezifische Zeichenfolgen in Kleinbuchstaben ab. Ich benutze Parser, weil die Eingabedaten eine gewisse Struktur haben, zB müssen literale Strings nicht transformiert werden. Gibt es eine elegante Möglichkeit, die Ausgabe eines Parsers als Eingabe für den nächsten zu verwenden und so eine Transformationspipeline zu bilden? Etwas in der Ader (was natürlich nicht funktioniert)?Parsec: Feed-Ausgabe von einem Parser zu einem anderen

Vielen Dank im Voraus!

+0

Ich glaube nicht, dass Sie so 'Parser' komponieren können, da sie beide aus dem zugrunde liegenden Stream lesen würden. Ich denke, Sie können besser als "String -> String" definieren, und wenn Sie eine 'Parser String' haben, die Sie normalisieren möchten, können Sie' fmap (normalizeWS. NormalizeCase) ''. – ryachza

Antwort

1

löste ich das Problem mit diesem Ansatz ... vielleicht gibt eine elegantere Möglichkeit

preprocessor :: Parser String 
preprocessor = normalizeCase `feeds` expandKettensatz `feeds` normalizeWs 

feeds :: Parser String -> Parser String -> Parser String 
feeds p1 p2 = do 
    s <- p1 
    setInput s 
    p2 
+0

Dies wird nicht gut komponieren: 'feeds p1 p2 >> p3' verhält sich nicht wie" konsumiere, was 'p1' verbraucht, übergebe das Ergebnis dieser Verbrauche an' p2', analysiere dann die verbleibende unverbrauchte Eingabe als 'p3' würde" . Und es ist nicht einfach, es so zu reparieren, dass es auch so funktioniert. sicherlich die offensichtlichste 'getInput' /' setInput' Gymnastik zur Behebung dieses speziellen Falles macht nur den Fehler subtiler, anstatt tatsächlich in allen Fällen zu arbeiten. –

0

Wenn Sie Funktionen wie

normalizeWhitespace :: Stream s m Char => ParsecT s u m String 
normalizeCase :: Stream s m Char => Set String -> Parsec s u m String 

Sie könnten ketten sie zusammen runParser und >>= mit haben, ist:

runBoth :: Stream s Identity Char => Set String -> SourceName -> s -> Either ParseError String 
runBoth wordSet src input = do 
    input <- runParser normalizeWhitespace() src input 
    runParser (normalizeCase wordSet)() src input 

Aber das gibt Ihnen keinen Parser das Sie können mit anderen Parsern zusammenarbeiten.

Dies ist nicht sehr überraschend, da Parser Zusammensetzung in Parsec alles über Komponieren Parser, die auf dem gleichen Strom arbeiten, während diese auf verschiedenen Streams operieren.

Mit mehreren verschiedenen Streams ist auch ziemlich häufig - mit der Ausgabe von a tokenization or lexing pass as input to parsing kann den Prozess zu verstehen, aber Parsec is a little easier to use out of the box as a direct parser (without lexing/tokenization) erleichtern.

Verwandte Themen