Se è possibile fattore parser1
in modo che si definisce in questo modo:
parser1 = (try parser2) <|> parser1extra
Allora il problema diventa un elenco di parser1extra
o parser2
che deve finire in un secondo momento. È possibile codificare che come:
parserList =
liftM2 (:) (try parser1extra) parserList
<|>
liftM2 (:) (try parser2) (option [] parserList)
si può o non hanno bisogno i try
chiamate a seconda se tali parser hanno alcuna sovrapposizione prefisso.
Se non si desidera che il valore di ritorno per essere un elenco, ma invece il vostro riferimento AParse, allora si potrebbe ri-scrivere in questo modo:
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)
Oppure, un esempio 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)
In realtà, le chiamate da provare non sono necessarie in questo caso, poiché parseNum
e parseWord
non corrispondono a nessun prefisso comune. Si noti che in realtà non parsePartListEndingInWord
riferimento parsePart
, ma, invece, le due opzioni che compongono la definizione parsePart
's
(risposta originale, risolvere una situazione un po' diversa :)
ne dite di qualcosa di simile a:
parserTest = between (char '[') (char ']') $ do
p1s <- try parser1 `endBy` char ','
p2 <- parser2
return $ AParse p1s p2
Prendendo la punteggiatura dai vostri parser e fino in parseTest consente di utilizzare i combinatori between
e endBy
a fare il lavoro per tu. Infine, lo try
è così che se parser1
e parser2
corrispondono a un prefisso comune, endBy
eseguirà il backup completo corretto all'inizio del prefisso comune.
A seconda delle parser, è possibile che si può lasciare l'abbinamento punteggiatura all'interno del vostro sub-parser, e tutto il necessario potrebbe essere l'una try
intorno parser1
:
parseTest = do parse1 <- many (try parser1)
parse2 <- parser2
return AParse parse1 parse2
ho commesso un errore nella questione e ha dichiarato che ho avuto un elenco di elementi. Dovrei dire che avevo una serie di elementi. Mi dispiace per quello Ho fatto la correzione nella domanda. Il secondo esempio nel codice non funzionerà perché parser1 consumerà l'intera stringa. – Chris
Grazie per il codice. Il parser1extra non consumerebbe semplicemente tutta la stringa? – Chris
L'idea era che parser1extra avrebbe solo analizzato quelle cose che dovrebbero essere in parser1, ma non corrispondono a parser2. Quindi parser1extra corrisponde solo a dove parser2 non lo fa. – MtnViewMark