我想我的輸入拆分成符合特定的圖案,其餘的那些部分,讓我們說非貪婪重複與秒差距
data Data = A Int | B Char | C String
parseDatas :: Parsec [Token]() a [Data]
我已經寫了兩個更多或更少的複雜解析器
parseA :: Parsec [Token]() Data
parseB :: Parsec [Token]() Data
匹配我正在尋找的東西。現在顯而易見的解決方案是
parseDatas = many (parseA <|> parseB <|> parseC)
其中對於中間部分的解析器是這樣的:
makeC :: [Token] -> Data
makeC = C . concatMap show -- or something like this
parseC :: Parsec [Token]() Data
parseC = makeC <$> many anyToken
咩,會拋出一個運行時[ERROR] Text.ParserCombinators.Parsec.Prim.many: combinator 'many' is applied to a parser that accepts an empty string.
- 好吧,容易固定:
parseC = makeC <$> many1 anyToken
但是現在parseC
消耗了整個輸入(開始於我不想要的東西),忽略了任何應該產生的模式A
或B
!
如果我的模式是正則表達式,我現在已經改變了+
運營商的非貪婪+?
運營商。我怎麼能爲many1
解析器組合器做同樣的事情?
1:我不能用,因爲我對令牌運行時,字符
一個解決方案,我發現這是
parseC = makeC <$> many1 (notFollowedBy (parseA <|> parseB) >> anyToken)
但看起來,嗯,不理想的。這不是通用的。必須有更好的東西。
我也看了一下Parsec how to find "matches" within a string其中建議是定義一個遞歸解析,但是這看起來像一個hazzle如果我不想丟棄中間的標記,並收集他們在一個列表來代替。
嗯,我的問題是我必須使用'makeC',它需要一個令牌列表。 'makeC。返回<$> anyToken'可以工作,但它看起來很醜,就像我目前的解決方案一樣低效。 – Bergi
@Bergi,以下是如何騰出空間來應用'make'。此外,這種方式奠定了「鏡頭」庫。 – Gurkenglas
@Bergi爲什麼你認爲'makeC。返回<$> anyToken'效率低下?它肯定不會像在你的問題中那樣執行任意前瞻。 –