On Tue, Feb 17, 2004 at 07:48:52PM +0000, Graham Klyne wrote:
> Thanks! That got me going, though not with quite what you suggested.
>> I ended up with this:
> [[
> notMatching :: Show a => GenParser tok st a -> GenParser tok st ()
> notMatching p = do { a <- try p ; unexpected (show a) } <|> return ()
> ]]
> which does the required job for me.
Oops, that does look better. I knew the try had to go somewhere. :-)
The only remaining problem is when p succeeds but does not consume any
input, eg eof. In this case, the <|> return () cannot distinguish it
from p failing.
I didn't realize at first what a dirty trick this function uses: It
distinguishes success or failure of p by whether any input from the
first part (before <|> return ()) was consumed. I don't think it is
possible (or desirable!) to get this approach 100% right: By "erasing"
the success of p, you lose the information you need.
What about a more prosaic implementation:
notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
notFollowedBy' p = do res <- do a <- try p; return $ Just a
<|>
return Nothing
case res of Just a -> unexpected (show a)
Nothing -> return ()
This works for the tests I've tried, but there's one little quirk with
error reporting:
aNoBC = do char 'a'
notFollowedBy' $ do char 'b'; char 'c'
*Main> parseTest (aNoBC >> char 'e') "abe"
parse error at (line 1, column 2):
unexpected "e"
expecting "c" or "e"
It seems that parsec both misreports which token is unexpected (should
be "b", and thinks that the failure to match "c" is a problem, even
though notFollowedBy' succeeded.
> Using your version caused the notMatching parser to be equivalent to:
> return ()
> presumably, because the failure was protected by the try combinator?
Or perhaps more accurately, the success (of p) was protected by the try!
Ie, the unexpected and the try together undid the tell-tale token
consumption of p.
Andrew