Question

Je voulais, juste pour apprendre un peu Iteratees, réimplémenter un analyseur simple que je fait, en utilisant Data.Iteratee et Data.Attoparsec.Iteratee. Je suis à peu près perplexe cependant. Ci-dessous j'ai un exemple simple qui est capable d'analyser un ligne à partir d'un fichier. Mon analyseur lit une ligne à la fois, donc je besoin d'un moyen d'alimentation des lignes à la iteratee jusqu'à ce qu'il soit fait. J'ai lu tous AVONS I trouvé googler, mais beaucoup de matériel sur iteratee / recenseurs est assez avancé. Ceci est la partie du code qui importe:

-- There are more imports above.
import Data.Attoparsec.Iteratee
import Data.Iteratee (joinI, run)
import Data.Iteratee.IO (defaultBufSize, enumFile)

line :: Parser ByteString -- left the implementation out (it doesn't check for 
                             new line)

iter = parserToIteratee line

main = do
    p <- liftM head getArgs
    i <- enumFile defaultBufSize p $ iter
    i' <- run i
    print i'

Cet exemple et imprimer une parse ligne à partir d'un fichier avec plusieurs lignes. Le script original cartographié l'analyseur sur une liste des chaînes d'octets. Donc, je voudrais faire la même chose ici. J'ai trouvé enumLinesin Iteratee, mais je ne peux pas pour la vie de me comprendre comment l'utiliser. Peut-être que j'ai mal compris son but?

Était-ce utile?

La solution

Étant donné que votre analyseur fonctionne sur une ligne à la fois, vous ne même pas besoin d'utiliser attoparsec-iteratee. Je voudrais écrire cela comme:

import Data.Iteratee as I
import Data.Iteratee.Char
import Data.Attoparsec as A

parser :: Parser ParseOutput
type POut = Either String ParseOutput

processLines :: Iteratee ByteString IO [POut]
processLines = joinI $ (enumLinesBS ><> I.mapStream (A.parseOnly parser)) stream2list

La clé pour comprendre c'est le « enumeratee », qui est juste le terme de iteratee pour un convertisseur de courant. Il faut un processeur de flux (iteratee) d'un type de flux et le convertit pour travailler avec un autre flux. Les deux enumLinesBS et mapStream sont enumeratees.

Pour mapper votre analyseur sur plusieurs lignes, mapStream suffit:

i1 :: Iteratee [ByteString] IO (Iteratee [POut] IO [POut]
i1 = mapStream (A.parseOnly parser) stream2list

Les iteratees imbriqués signifie simplement que ce convertit un flux de [ByteString] à un flux de [POut], et lorsque la iteratee finale (stream2list) est exécuté, il retourne ce flux comme [POut]. Alors maintenant, vous avez juste besoin l'équivalent iteratee de lines pour créer ce flux de [ByteString], qui est ce que enumLinesBS fait:

i2 :: Iteratee ByteString IO (Iteratee [ByteString] IO (Iteratee [POut] m [POut])))
i2 = enumLinesBS $ mapStream f stream2list

Mais cette fonction est assez difficile à manier à utiliser à cause de tout l'imbrication. Ce que nous voulons vraiment est un moyen de sortie de tuyau directement entre les convertisseurs courant, et au tout de la fin à un seul iteratee. Pour ce faire nous utilisons joinI, (><>) et (><>):

e1 :: Iteratee [POut] IO a -> Iteratee ByteString IO (Iteratee [POut] IO a)
e1 = enumLinesBS ><> mapStream (A.parseOnly parser)

i' :: Iteratee ByteString IO [POut]
i' = joinI $ e1 stream2list

ce qui équivaut à la façon dont je l'ai écrit ci-dessus, avec e1 inline.

Il est encore élément important reste cependant. Cette fonction renvoie simplement les résultats parse dans une liste. En général, vous voulez faire autre chose, comme combiner les résultats avec un pli.

edit: Data.Iteratee.ListLike.mapM_ est souvent utile de créer des consommateurs. A ce moment-là chaque élément du flux est un résultat d'analyse syntaxique, donc si vous voulez les imprimer, vous pouvez utiliser

consumeParse :: Iteratee [POut] IO ()
consumeParse = I.mapM_ (either (\e -> return ()) print)

processLines2 :: Iteratee ByteString IO ()
processLines2 = joinI $ (enumLinesBS ><> I.mapStream (A.parseOnly parser)) consumeParse

imprimera seulement les Parsis avec succès. Vous pouvez facilement rapporter des erreurs à STDERR, ou de les manipuler d'une autre manière, aussi bien.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top