Jeśli można czynnik parser1
tak że jest zdefiniowana tak:
parser1 = (try parser2) <|> parser1extra
Wtedy problemem staje się lista parser1extra
lub parser2
że musi kończyć się później. można kodować że:
parserList =
liftM2 (:) (try parser1extra) parserList
<|>
liftM2 (:) (try parser2) (option [] parserList)
pan może, ale nie musi połączeń try
zależności od tego czy te parser ma żadnego nakładania prefiksu.
Jeśli nie chcesz, wartość zwracana będzie na liście, ale zamiast Twój AParse punkt odniesienia, a następnie można ponownie zapisać go w ten sposób:
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)
Lub pełny przykład:
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)
W rzeczywistości połączenia do wypróbowania nie są w tym przypadku potrzebne, ponieważ parseNum
i parseWord
nie zawierają wspólnego przedrostka. Zauważ, że parsePartListEndingInWord
faktycznie nie odwoływać parsePart
, ale zamiast tego, obie opcje, które składają się na definicję parsePart
dydaktycznego
(odpowiedź oryginalny, rozwiązując nieco inną sytuację :)
Jak o coś takiego:
parserTest = between (char '[') (char ']') $ do
p1s <- try parser1 `endBy` char ','
p2 <- parser2
return $ AParse p1s p2
Biorąc interpunkcji z twoich parserami i aż do parseTest pozwala wykorzystać kombinatorów between
i endBy
do pracy dla ty. Na koniec znajduje się tam try
, więc jeśli parser1
i parser2
pasują do wspólnego prefiksu, endBy
wykona poprawną pełną kopię zapasową na początek wspólnego przedrostka.
zależności od parserami, możliwe jest, że można zostawić dopasowanie interpunkcyjny wewnątrz swoich podrzędnych parserami, a wszystko, co trzeba może być A try
wokół parser1
:
parseTest = do parse1 <- many (try parser1)
parse2 <- parser2
return AParse parse1 parse2
popełniłem błąd w pytaniu i stwierdził, że miałem listę elementów. Powinienem powiedzieć, że mam cały szereg przedmiotów. Przepraszam za to. Wprowadziłem poprawkę do pytania. Drugi przykład kodu nie zadziała, ponieważ parser1 zużyje cały ciąg. – Chris
Dzięki za kod. Czy parser1extra nie zużyje całego ciągu znaków? – Chris
Pomysł polegał na tym, że parser1extra analizowałby tylko te rzeczy, które powinny znajdować się w parser1, ale nie pasują do parser2. Dlatego parser1extra pasuje tylko wtedy, gdy parser2 tego nie robi. – MtnViewMark