2017-10-19 58 views
2

J'utilise des analyseurs (abus) pour effectuer une transformation de chaîne, par ex. normalizeWS :: Parser String supprime les espaces dupliqués et normalizeCase met en correspondance des chaînes spécifiques avec des minuscules. J'utilise des analyseurs syntaxiques parce que les données d'entrée ont une certaine structure, par exemple, les chaînes alphabétisées doivent être laissées non transformées. Existe-t-il un moyen élégant d'alimenter la sortie d'un analyseur en entrée et de former ainsi un pipeline de transformation? Quelque chose dans la veine de normalizeWS . normalizeCase (qui bien sûr ne fonctionne pas)?parsec: envoi de la sortie d'un parseur à un autre

Merci beaucoup d'avance!

+0

Je ne pense pas que vous puissiez composer 'Parser's de cette façon, car ils liraient tous les deux du flux sous-jacent. Je pense que vous pouvez mieux définir chacun comme 'String -> String', et quand vous avez un' Parser String' que vous aimeriez normaliser vous pourriez 'fmap (normalizeWS. NormalizeCase)'. – ryachza

Répondre

1

Je résolu le problème en utilisant cette approche ... peut-être il y a une façon plus élégante

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

Cela ne va pas bien se composer: 'feeds p1 p2 >> p3' ne se comporte pas comme "consomme ce que p1' consomme, passe le résultat de cette consommation à' p2', puis analyse l'entrée non consommée restante comme' p3' serait " . Et ce n'est pas facile de le réparer de cette façon, soit, malheureusement; la gymnastique 'getInput' /' setInput' la plus évidente pour réparer ce cas particulier rend certainement le bug plus subtil que fonctionnel dans tous les cas. –

0

Si vous avez des fonctions telles que

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

Vous pouvez les enchaîner en utilisant runParser et >>=:

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 

Mais cela ne vous donne pas un analyseur vous pouvez enchaîner avec d'autres parseurs.

Ce n'est pas très surprenant, car la composition de l'analyseur dans Parsec est tout au sujet composition des analyseurs syntaxiques qui fonctionnent sur le même flux, alors que ceux-ci fonctionnent sur différents flux. Avoir plusieurs flux différents est assez commun aussi - en utilisant la sortie de a tokenization or lexing pass as input to parsing peut faciliter le processus pour comprendre, mais Parsec is a little easier to use out of the box as a direct parser (without lexing/tokenization).