[Haskell-cafe] Re: [Haskell Cafe] Parsec: using two different
parser for the same string
psujkov at gmail.com
Wed Aug 5 13:51:36 EDT 2009
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 <psujkov at gmail.com>
> 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
> *Parlog> parseTest parseIntList "(1;2;3;4)"
> *Parlog> parseTest parseIntString "(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
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Haskell-Cafe