あなたがparser1そのように定義されるように因数分解することができるならば:
parser1 = (try parser2) <|> parser1extra
次に、問題はリストになるparser1extraかparser2、後で終了する必要があります。次のようにコーディングできます。
parserList =
liftM2 (:) (try parser1extra) parserList
<|>
liftM2 (:) (try parser2) (option [] parserList)
tryそれらのパーサーにプレフィックスの重複があるかどうかに応じて、呼び出しが必要な場合と不要な場合があります。
戻り値をリストにしたくないが、代わりにAParseデータムにしたい場合は、次のように書き直すことができます。
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)
または、完全な例:
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)
実際には、この場合、共通のプレフィックスparseNumと一致しないため、tryの呼び出しは必要ありません。実際には参照していませんが、代わりに、の定義を構成する2つのオプションにparseWord注意してください。parsePartListEndingInWordparsePartparsePart
(元の答え、多少異なる状況を解決する:)
次のようなものはどうですか?
parserTest = between (char '[') (char ']') $ do
p1s <- try parser1 `endBy` char ','
p2 <- parser2
return $ AParse p1s p2
パーサーから句読点を取り出してparseTestに入れると、コンビネーターを使用betweenしendByて作業を行うことができます。最後に、共通プレフィックスと一致するtry場合、共通プレフィックスの先頭への正しい完全バックアップを実行するためにあります。parser1parser2endBy
パーサーによっては、句読点をサブパーサー内に一致させたままにしておくことができます。必要なのは、try周りだけparser1です。
parseTest = do parse1 <- many (try parser1)
parse2 <- parser2
return AParse parse1 parse2