Si puede factorizar parser1
de manera que se define así:
parser1 = (try parser2) <|> parser1extra
Entonces, el problema se convierte en una lista de parser1extra
o parser2
que debe terminar en la tarde. Puede codificar que a medida:
parserList =
liftM2 (:) (try parser1extra) parserList
<|>
liftM2 (:) (try parser2) (option [] parserList)
Usted puede o no puede necesitar los try
llamadas dependiendo de si esos analizadores tienen ningún solapamiento prefijo.
Si no desea que el valor de retorno sea una lista, pero en cambio su dato AParse, entonces se podría volver a escribir de esta manera:
parserList =
do
a <- try parser1extra
prefix a parserList
<|>
do
a <- try parser2
option (AParse [] a) (prefix a parserList)
where prefix a p = do
(AParse as t) <- p
return $ (AParse (a:as) t)
O, un ejemplo completo:
import Control.Monad
import Text.ParserCombinators.Parsec
parseNum = do { v <- many1 digit; spaces; return v }
parseWord = do { v <- many1 letter; spaces; return v }
parsePart = parseNum <|> parseWord
parsePartListEndingInWord =
liftM2 (:) (try parseNum) parsePartListEndingInWord
<|>
liftM2 (:) (try parseWord) (option [] parsePartListEndingInWord)
En realidad, las llamadas a intentar no son necesarias en este caso, ya que parseNum
y parseWord
no coinciden con el prefijo común. Observe que parsePartListEndingInWord
en realidad no hacer referencia a parsePart
, pero en su lugar, las dos opciones que componen la definición parsePart
's
(Respuesta original, resolver una situación algo diferente :)
¿Qué tal algo así como:
parserTest = between (char '[') (char ']') $ do
p1s <- try parser1 `endBy` char ','
p2 <- parser2
return $ AParse p1s p2
Tomando la puntuacion de los analizadores y hasta en parseTest le permite utilizar los combinadores between
y endBy
a hacer el trabajo por tú. Por último, el try
está allí para que si parser1
y parser2
coinciden con un prefijo común, endBy
realizará la copia de seguridad completa correcta al comienzo del prefijo común.
Dependiendo de sus programas de análisis, es posible que se puede dejar el juego puntuacion dentro de sus sub-programas de análisis, y todo lo que necesita podría ser el de un try
alrededor parser1
:
parseTest = do parse1 <- many (try parser1)
parse2 <- parser2
return AParse parse1 parse2
he cometido un error en la pregunta y me dijo que tenía una lista de elementos. Debo decir que tengo una cadena de artículos. Lo siento por eso. Hice la corrección en la pregunta. El segundo ejemplo en el código no funcionará porque el analizador 1 consumirá toda la cadena. – Chris
Gracias por el código. ¿No usaría parser1extra solo toda la cadena? – Chris
La idea era que parser1extra solo analizara aquellas cosas que deberían estar en parser1, pero que no coinciden con parser2. Por lo tanto, parser1extra solo coincide donde parser2 no coincide. – MtnViewMark