
Well, I was too optimistic saying "I can return the updated state". I don't
know how to do that actually. Maybe someone else here knows?
2009/8/5 Paul Sujkov
Hi everybody,
suppose I have two different parsers: one just reads the string, and another one parses some values from it. E.g.:
parseIntList :: Parser [Integer] parseIntList = do char '(' res <- liftM (map read) (sepBy1 (many1 digit) (char ';')) char ')' return res
parseIntString :: Parser String parseIntString = manyTill anyChar eof
so for some input like this - "(1;2;3;4)" - I will have two different result:
*Parlog> parseTest parseIntList "(1;2;3;4)" [1,2,3,4] *Parlog> parseTest parseIntString "(1;2;3;4)" "(1;2;3;4)"
but the thing that I actually want is something like Parser ([Integer], String) - results from both parsers at a time, no matter whether one of them fails or not:
*Parlog> parseTest parseIntListAndString "(1;2;3;4)" ([1,2,3,4], "(1;2;3;4)")
it is impossible at first sight, because first parser to use will consume all the input, and there will be nothing to parse for the second one
Parsec contains "choice" function, but it is implemented via <|> and that is mplus - so it tries second alternative only if the first one fails. Is it possible to use two parsers for the same string (with try-like backtracking, no input actually consumed till the second parser finishes)? I can assume only dirty hacks with the GenParser internals - manual position storing and backtracking - but that is obviously not good
however, my first attempt to solve the problem was kind a like that: to parse string to String, and then to use it as an input for the next level parse call:
parseIntListAndString :: Parser ([Integer], String) parseIntListAndString = do str <- parseIntString return (res str, str) where res str = case (parse parseIntList "" str) of Left err -> [] Right val -> val
but the problems with such a method began when I switched from Parser to GenParser with user state: function parseIntList have to update the state, but it can't have the same state as the parseIntListAndString any more: it has it's own. I can explicitly pass the state from parseIntListAndString to parseIntList, but I see no suitable way for the parseIntList to update it. I can return the updated state value from the parseIntList function, and call setState on a result - but it seems rather ugly to mee. However, if nothing else will do, that is an alternative
it is of course possible to use two different parsers sequentially, but it is also very ineffective: I need to use such multiple parsing on a relatively small substring of the actual input, so little backtracking would be a much nicier approach. Any suggestions?
-- Regards, Paul Sujkov
-- Regards, Paul Sujkov