0
votes

I would like to write a Parsec parser that would parse a sequence of numbers, returning a sorted list, but failing on encountering a duplicate number (the error should point to the position of the duplicate). For the sorted part I can simply use:

manySorted = manyAccum insert

But how can I trigger a Parsec error if the number is already on the list. It doesn't seem like manyAccum allows that and I couldn't figure out how to make my own clone of manyAccum that would (implementation uses unParser which doesn't seem to be exposed outside of Parsec library).

2
Are you sure that's a job for the parser? Typically that type of behavior goes in a different part of the process.Benjamin Kovach
Try first parse all the numbers, then check all necessary conditions. This way you can easily throw an exception or return Left for example.Mark Karpov
That's what I'm doing now, but it would be nice to get location of the duplicate in the error message. I guess the number parser could get location from the parser state and return it along with the result so that it can be used later for the error. Is that the right pattern to use for a case like this?kruipen

2 Answers

1
votes

You could try to obtain the current parser's position by

sourcePos :: Monad m => ParsecT s u m SourcePos
sourcePos = statePos `liftM` getParserState

Then accumulate the positions together with parsed values so that you can report the position of the original.

0
votes

If you're sure you want the parser to be doing this, you can use the fail method with an error message to fail out of the parser. (Complete with an error location, and trying other <|> possibilities, and so on.)