[Haskell-cafe] Re: [Haskell Cafe] Parsec: using two different parser for the same string

Paul Sujkov 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
> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20090805/e52207ea/attachment.html


More information about the Haskell-Cafe mailing list