Parsing whitespace before or-else with Parsec

1.4k views Asked by At

I am using the Parsec module in Haskell to parse files. One of the components of these files are colors. I have created a type for colors like this:

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

My initial attempt at parsing colors looks like this:

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

I created the symbol parser which basically eats as much whitespace as possible and then eats the given string s. However, this does not seem to work. I test this code with the following call:

parse colorP "" "        Red"

This gave me the following error:

unexpected "R"
expecting space or "Yellow"

However, I went looking on Hoogle for the documentation that goes with the <|> operator and there I found the following:

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.

So, I think the problem with the above example is that parser p (in this case symbol "Yellow") already did consume some input, namely the blanks! So, I refactored my colorP like this:

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

which gives the result I want.

Now, I am wondering if there is no parser like the symbol parser that I wrote, but that puts back the input in case of a failure. Or is the second implementation of colorP the one that is most Haskell-ish?

1

There are 1 answers

0
ptixed On BEST ANSWER

You could use 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.