[Haskell-cafe] Parsec question

Daniel Fischer daniel.is.fischer at web.de
Fri Apr 17 20:50:33 EDT 2009


Am Samstag 18 April 2009 01:33:44 schrieb Michael P Mossey:
> I've just about got this parser working, but wondering about something.
> Turns out I need "try" inside the "lookahead" here.
>
> parseText :: Parser String
> parseText = manyTill anyChar $ lookAhead (try (string "//"))
>
> Without try, if I give it an input with a single slash, like
>
> "some/text"
>
> It stops with the error "unexpected t; expecting //"
>
>
> I'm curious why that happens when lookAhead is used with manyTill like
> this. I was under the impression that if the end parser given to manyTill
> failed, then manyTill would just continue with the main parser. Apparently
> there are two ways to fail: in some contexts, failing means that manyTill
> will just continue. In other contexts, such as the one above, there is some
> sense in which 'string' demands the entire string to be present. Can anyone
> explain?
>

Looking at the source:


manyTill :: GenParser tok st a -> GenParser tok st end -> GenParser tok st [a]
manyTill p end      = scan
                    where
                      scan  = do{ end; return [] }
                            <|>
                              do{ x <- p; xs <- scan; return (x:xs) }

if end fails after consuming some input, manyTill p end fails.


lookAhead :: GenParser tok st a -> GenParser tok st a
lookAhead p         = do{ state <- getParserState
                        ; x <- p
                        ; setParserState state
                        ; return x
                        }

lookAhead fails if p fails, but if p fails, the state is not reset, so if p fails after 
consuming some input, like in your example "some/text", where lookAhead (string "//") 
consumes the slash and fails because the second expected slash is missing, that is not put 
back and since something is consumed, the second branch of scan in manyTill isn't tried.

You could also have

keyword = try $ do
    string "//"
    kw <- many1 keywordChar
    return (Keyword kw)

parseText = manyTill anyChar (lookAhead keyword)

Seems cleaner to have the slashes in keyword.


> Thanks,
> Mike
>

Cheers,
Daniel



More information about the Haskell-Cafe mailing list