many turns a parser for one value into a parser for a list of values. It accepts zero or more consecutive matches: a parser for 'a' can therefore succeed on "aaa" with three characters and on "b" with an empty list. Returning the list keeps repetition general; counting, collecting, or further transformation can be chosen afterward. section 9.2 section 9.8
Count repeated characters
Rather than make repetition return a count, first retain every match and then map the list to its size: char('a').many.map(_.size). This yields 3 for "aaa" and 0 for "b". map changes only a successful result value; it neither examines additional input nor changes success into failure. section 9.2
A list is not always the desired result. slice runs a parser to obtain the matched input portion instead. Thus (char('a') | char('b')).many.slice parses "aaba" as "aaba". For counting repeated 'a' characters, char('a').many.slice.map(_.size) avoids constructing a list merely to discard it. section 9.2.1
many describes optional repetition; many1 describes required repetition. The latter need not be primitive: parse one value, parse many more, then cons the first value onto the remaining list. product and map2 provide the sequencing and result combination needed for this definition. section 9.2.1 section 9.8
extension [A](p: Parser[A]) def many: Parser[List[A]] = p.map2(p.many)(_ :: _) | succeed(Nil)
The direct recursive shape is: parse one value and recurse, or succeed with Nil. Its recursive parser argument must be deferred; a strict map2 evaluates p.many too early and can overflow the stack. section 9.2.1 section 9.8
Use many as a building block for related repetition patterns:
- Define many1 by combining p with p.many and consing the first result onto the list. section 9.8
- Define listOfN similarly, stopping with Nil when the requested count reaches zero. section 9.8
- Parse separator-delimited values by parsing one value followed by many occurrences of separator then value. section 9.8
