I'm trying to parse some Text with parsec:
data Cmd = LoginCmd String
| JoinCmd String
| LeaveCmd String
deriving (Show)
singleparam :: Parser Cmd
singleparam = do
cmd <- choice [string "leave", string "login", string "join"]
spaces
nick <- many1 anyChar
eof
return $ LoginCmd nick
I'm expecting choice
to try to match "leave", and if it fails, then try "login" etc. But it only tries to match "leave", and if it fails, then gives an error.
ghci> parseTest singleparam (pack "login asdf")
parse error at (line 1, column 1):
unexpected "o"
expecting "leave"
ghci> parseTest singleparam (pack "leave asdf")
LoginCmd "asdf"
What am I doing wrong?
Parsec does not automatically backtrack like this (for efficiency). The rule is that once a branch accepts a token then alternative branches are pruned. The solution is to add an explicit backtracking using try (string "leave")
and try (string "login")
etc.
In your example the 'l' character is the token that commits Parsec to the first "leave" branch and abandons the next branches of "login" and "join".
More detail in Real World Haskell (book, online) on parsec.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With