【问题标题】:Haskell parsec: `many` combinator inside an `optional` combinatorHaskell parsec:“可选”组合器中的“许多”组合器
【发布时间】:2016-01-19 01:47:10
【问题描述】:

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

((a | b | c)* (a | b))?

这是一个接受可选(即可能为空)字符串的解析器规则。如果它接受的字符串不为空,则可以通过传递零次或多次出现的abc 解析器来使用它,但最外面的? 可选解析器接受的字符串必须被解析器ab 使用,但不是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

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

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

many 只消耗每个测试用例中的所有“a”、“b”和“c”字符,而a &lt;|&gt; b 没有可消耗的字符。

问题

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

【问题讨论】:

  • 也许解析 (a|b|c)+ 并在以 c 结尾时拒绝它?

标签: haskell parsec


【解决方案1】:

我们也可以稍有不同:解析器中的c 可能只有在其后跟任何标记时才能成功,这可以通过单个lookAhead 来完成:

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

【讨论】:

  • 谢谢,这行得通。我有一半期望它不起作用,因为anyToken 我以为只是那个意思,无论是“d”、“\n”还是其他什么。我在想myParser = many (a &lt;|&gt; b &lt;|&gt; (c &lt;* (lookAhead (try a &lt;|&gt; try b) &lt;?&gt; "non C token"))) &lt;* eof之类的东西。但是,您对myParser 的定义确实 有效。例如。解析“ca”返回“ca”,而尝试解析“cd”失败,出现“意外的'd'。期待“a”、“b”、“c”或输入结束”。为什么anyToken 组合子只愿意接受'a'、'b'或'c'?
  • @RobStewart:由于&lt;* eofmyParser 期望消耗所有输入。
猜你喜欢
  • 2011-01-27
  • 2014-05-30
  • 2011-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-18
  • 1970-01-01
相关资源
最近更新 更多