Pregunta

Estoy convirtiendo un código de Haskell en funcionamiento que usa Parsec para usar AtToparSec con la esperanza de obtener un mejor rendimiento. He realizado los cambios y todo lo que se compila, pero mi analizador no funciona correctamente.

Estoy analizando un archivo que consta de varios tipos de registro, uno por línea. Cada una de mis funciones individuales para analizar un registro o comentario funciona correctamente, pero cuando trato de escribir una función para compilar una secuencia de registros, el analizador siempre devuelve un resultado parcial porque espera más entrada.

Estas son las dos variaciones principales que he probado. Ambos tienen el mismo problema.

items :: Parser [Item]
items = sepBy (comment <|> recordType1 <|> recordType2) endOfLine

Para este segundo cambié los analizadores de registro/comentarios para consumir los personajes de fin de línea.

items :: Parser [Item]
items = manyTill (comment <|> recordType1 <|> recordType2) endOfInput

¿Hay algo de malo en mi enfoque? ¿Hay alguna otra forma de lograr lo que estoy intentando?

¿Fue útil?

Solución

Me he encontrado con este problema antes y tengo entendido que es causado por la forma en que <|> funciona en la definición de sepBy:

sepBy1 :: Alternative f => f a -> f s -> f [a]
sepBy1 p s = scan
    where scan = liftA2 (:) p ((s *> scan) <|> pure [])

Esto solo se moverá a pure [] una vez (s *> scan) ha fallado, lo que no sucederá solo porque estás al final de la entrada.

Mi solución ha sido solo llamar feed con un empty Bytestring en el Result devuelto por parse. Esto podría ser una especie de truco, pero también parece ser como attoparsec-iteratee se ocupa del problema:

f k (EOF Nothing)  = finalChunk $ feed (k S.empty) S.empty

Por lo que puedo decir, esta es la única razón por la que attoparsec-iteratee funciona aquí y sencillo viejo parse no.

Otros consejos

Si escribe un analizador AtToparSec que consume tanta entrada como sea posible antes de fallar, debe indicar la continuación parcial de los resultados cuando llegue al final de su entrada.

Da bastante poca información, por lo que creo que es difícil brindarle buena ayuda. Sin embargo, hay un par de comentarios que me gustaría dar:

  • Quizás el analizador no se dé cuenta de que la entrada está realizada y depende de obtener una EOL o obtener otro registro. Por lo tanto, solicita un resultado parcial. Intente alimentarlo con el equivalente de EOL con la esperanza de que lo obliga.
  • No recuerdo el código, pero usar la instancia alternativa puede ser perjudicial para el rendimiento de análisis. Si ese es el caso, es posible que desee divulgar el comentario y los registros.
  • Utilizo cereal para un gran análisis binario y eso también es extremadamente rápido. Sin embargo, Attoparsec parece mejor como un texto de texto. Definitivamente deberías considerar la opción.
  • Otra opción es usar IO basado en ITATEE en la ejecución más larga. John Lato hizo un excelente artículo sobre iterado en el último lector de Mónadas (Número 16, creo). La condición de fin de línea es el iterado para señalar. Sin embargo, tenga cuidado de que los tipos de Itereree sean bastante desalentadores y se tomen un tiempo acostumbrarse.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top