[Haskell-beginners] writing many1Till combinator for Parsec
Vlad Skvortsov
vss at 73rus.com
Mon Dec 14 17:35:13 EST 2009
Daniel Fischer wrote:
> You want a nonempty sequence of 'p's which aren't 'end's, followed by an 'end'.
> So you could do for example
> a)
> many1Till p end = do
> ps <- manyTill p end
> guard (not $ null ps)
> return ps
>
> , i.e. check whether the result of manyTill is a nonempty list after the fact, or check
> whether manyTill p end will return an empty list before manyTill is run, like
> b)
> many1Till p end = do
> notFollowedBy end
> manyTill p end
>
> (i.e. many1Till p end = notFollowedBy end >> manyTill p end).
>
Thanks Daniel! I missed out on 'guard' and somewhy was under impression
that 'notFollowedBy' can only deal with Chars.
>> many1Till :: Parser a -> Parser end -> Parser [a]
>> many1Till p end = do
>> try (end >> (unexpected "sequence terminator"))
>> <|> (do { p1 <- p; ps <- manyTill p end; return (p1:ps) })
>>
>> Here there are two disadvantages:
>>
>> 1) I don't like hardcoding "sequence terminator" here;
>> 2) the error output should say that only 'p' parser is expected, while
>> it says (technically correct) that either 'p' or 'end' is expected:
>>
>> Prelude Main Text.ParserCombinators.Parsec> parseTest (many1Till letter
>> (char '.')) "1"
>> parse error at (line 1, column 1):
>> unexpected "1"
>> expecting "." or letter
>>
>> (What I want here is to say "expecting letter")
>>
>
> For that, you need the slightly clumsier
> c)
> many1Till p end = do
> notFollowedBy end
> p1 <- p
> ps <- manyTill p end
> return (p1:ps)
>
Yep, that works but still provides incorrect diagnostics when fed with
an empty string:
Prelude Main Text.ParserCombinators.Parsec> parseTest (many1Till letter
(char '.')) ""
parse error at (line 1, column 1):
unexpected end of input
expecting "." or letter
It's not a showstopper, but I'd still like to understand how to make it
provide better error messages.
Thanks!
--
Vlad Skvortsov, vss at 73rus.com, http://vss.73rus.com
More information about the Beginners
mailing list