[Haskell-cafe] Poor Parsec error message

Lyle Kopnicky lists at qseep.net
Thu Jul 10 11:15:14 EDT 2008

I figured it out, but it's not pretty. The problem is that the eof 
parser had no awareness of the showTok function. To fix the problem, I 
had to replace eof with its definition in terms of notFollowedBy, then 
replace notFollowedBy with its definition in terms of try and 
unexpected. Then, I changed the "show [c]" into "showToken c".

Passing a token shower to the token function isn't a very robust way of 
guaranteeing your tokens display properly in error messages, because the 
other combinators don't take the same option. Of course, you can 
implement a Show instance for your tokens as you like. But, if you make 
the Show instance show the pretty version for the user, you lose the 
ability to see the real structure you get from a derived Show instance. 
In my real code, I want debugging to show tokens using a derived Show 
instance, so I can see all the structure. But when I show them to the 
user, I don't want them to see the embedded SourcePos, or the 
constructor names - I just want them to see a representation of what was 
lexed in order to produce that token.

I think there should be a class called Token, with a method called 
showToken, or unlex, or display, or displayInError, something like that. 
This class should be a precondition of all the GenParser combinators. It 
should use the provided method to show the token in error messages.

Here's the working version:

import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Pos(newPos)

showToken (pos,t) = "<" ++ show t ++ ">"

myToken :: (Eq t, Show t) => (t -> Bool) -> GenParser (SourcePos,t) () 
myToken q = token showToken posFromTok testTok where
    posFromTok (pos,t) = pos
    testTok (pos,t) = if (q t) then Just (pos,t) else Nothing

main = do
    putStrLn ""
    case parse the123Parser "" [(newPos "" 1 n, n) | n <- [1,2,3,4]] of
        (Left err) -> putStrLn (show err)
        (Right _) -> putStrLn "parsed correctly"
    putStrLn ""
    case parse the123Parser "" [(newPos "" 1 n, n) | n <- [1,3,4]] of
        (Left err) -> putStrLn (show err)
        (Right _) -> putStrLn "parsed correctly"

the123Parser = do
    myToken (==1)
    myToken (==2)
    myToken (==3)
    try (do{ c <- myToken (const True); unexpected (showToken c) } <|> 
return ())
    notFollowedBy (myToken (==4))
    return 123

- Lyle

More information about the Haskell-Cafe mailing list