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?

Était-ce utile?

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.
scroll top