Haskell parsec:`many` combinator在`optional`组合器中

Rob*_*art 9 haskell parsec

我想使用Haskell的parsec库实现这个语法规则:

((a | b | c)* (a | b))?
Run Code Online (Sandbox Code Playgroud)

哪个是接受可选(即可能为空)字符串的解析器规则.如果它所接受的字符串不为空,则可以通过传递零次或多次出现的a b或者c解析器来使用它,但是最外部?可选解析器所接受的字符串必须由解析器消耗,a或者b不是c.这是一个例子:

module Main where

import Text.Parsec
import Text.Parsec.Text

a,b,c :: GenParser () Char
a = char 'a'
b = char 'b'
c = char 'c'

-- ((a | b | c)* (a | b))?
myParser = undefined

shouldParse1,shouldParse2,shouldParse3,
      shouldParse4,shouldFail :: Either ParseError String
-- these should succeed
shouldParse1 = runParser myParser () "" "" -- because ? optional
shouldParse2 = runParser myParser () ""  "b"
shouldParse3 = runParser myParser () "" "ccccccb"
shouldParse4 = runParser myParser () "" "aabccab"

-- this should fail because it ends with a 'c'
shouldFail = runParser myParser () "" "aabccac"

main = do
  print shouldParse1
  print shouldParse2
  print shouldParse3
  print shouldParse4
  print shouldFail
Run Code Online (Sandbox Code Playgroud)

第一次尝试可能如下所示:

myParser = option "" $ do
  str <- many (a <|> b <|> c)
  ch  <- a <|> b
  return (str ++ [ch])
Run Code Online (Sandbox Code Playgroud)

但是many在每个测试用例中只消耗所有"a","b"和"c"字符,a <|> b不会消耗任何字符.

问题:

使用parsec组合器,((a | b | c)* (a | b))?定义的正确实现是myParser什么?

Zet*_*eta 4

我们还可以稍微不同地说明这一点:c在您的解析器中,只有在后面跟有任何标记时才可能成功,这可以通过单个来完成lookAhead

myParser = many (a <|> b <|> (c <* (lookAhead anyToken <?> "non C token"))) <* eof
Run Code Online (Sandbox Code Playgroud)