使用 Parsec 解析 or-else 之前的空格

Parsing whitespace before or-else with Parsec

我正在使用 Haskell 中的 Parsec 模块来解析文件。这些文件的组成部分之一是颜色。我为这样的颜色创建了一个类型:

data Color = Yellow | Red | Blue | Green deriving (Show)

我最初尝试解析颜色是这样的:

symbol :: String -> Parsec String () String
symbol s = spaces >> string s

colorP :: Parsec String () Color
colorP = 
   liftM mkColor $ symbol "Yellow" <|> symbol "Red" <|> symbol "Blue" <|> symbol "Green"
  where
   mkColor :: String -> Color
   mkColor "Yellow" = Yellow
   mkColor "Red" = Red
   mkColor "Blue" = Blue
   mkColor "Green" = Green

我创建了 symbol 解析器,它基本上吃掉尽可能多的空格,然后吃掉给定的字符串 s。但是,这似乎不起作用。我使用以下调用测试此代码:

parse colorP "" "        Red"

这给了我以下错误:

unexpected "R"
expecting space or "Yellow"

但是,我继续在 Hoogle 上查找与 <|> 运算符一起使用的文档,并在那里找到了以下内容:

This combinator implements choice. The parser p <|> q first applies p. If it succeeds, the value of p is returned. If p fails without consuming any input, parser q is tried.

因此,我认为上述示例的问题在于解析器 p(在本例中为 symbol "Yellow")已经消耗了一些输入,即空白!所以,我像这样重构了我的 colorP

colorP =
  liftM mkColor $ spaces >> (string "Yellow" <|> string "Red" <|> string "Blue" <|> string "Green")
 where
   -- mkColor same as before

这给出了我想要的结果。

现在,我想知道是否没有像我编写的 symbol 解析器那样的解析器,但它会在出现故障时返回输入。或者 colorP 的第二个实现是最 Haskell-ish 的那个?

您可以使用 try

symbol s = try (spaces >> string s)

The parser try p behaves like parser p, except that it pretends that it hasn't consumed any input when an error occurs.