あなたが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
注意してください。parsePartListEndingInWord
parsePart
parsePart
(元の答え、多少異なる状況を解決する:)
次のようなものはどうですか?
parserTest = between (char '[') (char ']') $ do
p1s <- try parser1 `endBy` char ','
p2 <- parser2
return $ AParse p1s p2
パーサーから句読点を取り出してparseTestに入れると、コンビネーターを使用between
しendBy
て作業を行うことができます。最後に、共通プレフィックスと一致するtry
場合、共通プレフィックスの先頭への正しい完全バックアップを実行するためにあります。parser1
parser2
endBy
パーサーによっては、句読点をサブパーサー内に一致させたままにしておくことができます。必要なのは、try
周りだけparser1
です。
parseTest = do parse1 <- many (try parser1)
parse2 <- parser2
return AParse parse1 parse2