Thanks. So I tried

upTo n p =
    liftM2 (:) p (upTo (n-1) p)

which doesn't quite work because the recursion does not have a base case. The following gets me closer:

upTo n p =
    if n <= 0 then
        return []
    else
        liftM2 (:) p (upTo (n-1) p)

> parse (upTo 3 digit) "" "123ab"
Right "123"

However:

> parse (upTo 4 digit) "" "123ab"
Left (line 1, column 4):
unexpected "a"
expecting digit

The semantics of (upTo n p) should be to parse at most n tokens, but if less than n tokens are available that should still be a successful parse. And the next token should be the first one upTo failed on.

I attempted to use the "try" parser in various locations but that doesn't seem to help, or maybe I'm using it incorrectly.


On Sat, Oct 17, 2009 at 5:15 AM, Christian Maeder <Christian.Maeder@dfki.de> wrote:
Ashish Agarwal schrieb:
> Hi. I'm just learning Parsec and Haskell. It is a great library, and I
> see how "many" lets you parse 0 or more items, "many1" parses 1 or more
> items, and "count" parses exactly n items. However, there is no
> combinator that parses between m and n items. What would be the best
> implementation for this?

I would write an "upTo" parser with the same type as "count" that parses
not exactly but at most n items. Your desired parser is than the
concatenated results of "count m p" and "upTo (n - m) p" (achieved by
"liftM2 (++)").

For "upTo" a recursive definition seems best (other may come up with
tricky combinator application.) "upTo 0 p" (or something less than 0)
returns "[]" and "upTo n p" is an "option [] ..." parser of one "p"
result followed by the "upTo (n - 1) p" result:

"option [] (liftM2 (:) p (upTo (n - 1) p))"

HTH Christian

Another possibility is to use "many" and check if the resulting list has
the desired length (if not fail), but that may consume too many tokens
that subsequent parsers are supposed to consume.