Problème avec l'entrée incomplète lors de l'utilisation Attoparsec
-
24-10-2019 - |
Question
Je suis en train de convertir un certain fonctionnement du code Haskell qui utilise parsec utiliser à la place Attoparsec dans l'espoir d'obtenir de meilleures performances. J'ai fait les changements et tout mon analyseur compile, mais ne fonctionne pas correctement.
Je suis l'analyse d'un fichier qui se compose de différents types d'enregistrement, une par ligne. Chacune de mes différentes fonctions pour l'analyse d'un enregistrement ou commentaire fonctionne correctement mais lorsque je tente d'écrire une fonction pour compiler une séquence d'enregistrements l'analyseur renvoie toujours un résultat partiel parce qu'il attend plus d'entrée.
Ce sont les deux principales variations que je l'ai essayé. Les deux ont le même problème.
items :: Parser [Item]
items = sepBy (comment <|> recordType1 <|> recordType2) endOfLine
Pour cette seconde j'ai changé le record / commentaire parseurs consommer les caractères de fin de ligne.
items :: Parser [Item]
items = manyTill (comment <|> recordType1 <|> recordType2) endOfInput
Y at-il quelque chose de mal avec mon approche? Y at-il une autre façon de réaliser ce que je tente?
La solution
J'ai rencontré ce problème avant et je crois comprendre qu'il est causé par la façon dont fonctionne <|>
dans la définition de sepBy
:
sepBy1 :: Alternative f => f a -> f s -> f [a]
sepBy1 p s = scan
where scan = liftA2 (:) p ((s *> scan) <|> pure [])
Cela ne se déplacera à pure []
fois (s *> scan)
a échoué, ce qui ne se produira pas parce que vous êtes à la fin de l'entrée.
Ma solution a été juste pour appeler feed
avec un ByteString de empty
sur le Result
retourné par parse
. Cela pourrait être une sorte de hack, mais il semble aussi être comment offres de attoparsec-iteratee
avec la question:
f k (EOF Nothing) = finalChunk $ feed (k S.empty) S.empty
Pour autant que je peux dire que c'est la seule raison pour laquelle attoparsec-iteratee
travaille ici et ancienne plaine parse
ne fonctionne pas.
Autres conseils
Si vous écrivez un analyseur attoparsec qui consomme le plus d'information possible avant défaut, vous devez dire la continuation de résultat partiel lorsque vous avez atteint la fin de votre entrée.
Vous donner assez peu d'informations qui est pourquoi je pense qu'il est difficile de vous donner une bonne aide. Cependant, il y a quelques commentaires que je voudrais donner:
- Peut-être que l'analyseur ne se rend pas compte que l'entrée se fait et il dépend soit d'obtenir un EOL ou d'obtenir un autre record. Par conséquent, il demande un résultat partiel. Essayez le nourrir l'équivalent de EOL dans l'espoir qu'elle le force.
- Je ne me souviens pas du code, mais en utilisant l'instance alternative pourrait nuire à la performance de l'analyse. Si tel est le cas, vous voudrez peut-être le cas sur le commentaire et recordTypes.
- J'utilise des céréales pour beaucoup d'analyse syntaxique binaire et qui est aussi extrêmement rapide. attoparsec semble mieux comme un analyseur de texte bien. Vous devriez certainement envisager l'option.
- Une autre option consiste à utiliser iteratee basée sur IO à plus long terme. John Lato a fait un excellent article sur iteratees dans le dernier lecteur de monade (question n ° 16 je crois). La condition de fin de ligne est le iteratees de signaux. Attention cependant que les types de iteratee sont assez intimidante et prendre un certain temps pour s'y habituer.