Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Text.Parsec.Combinator choice doesn't backtrack

Tags:

haskell

parsec

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?

like image 542
sinan Avatar asked Apr 02 '12 12:04

sinan


1 Answers

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.

like image 72
Chris Kuklewicz Avatar answered Oct 27 '22 15:10

Chris Kuklewicz