parser-combinators icon indicating copy to clipboard operation
parser-combinators copied to clipboard

[Proposal] Add manyEndingWith

Open lsmor opened this issue 1 year ago • 2 comments

Hi! may you consider adding manyEndingWith (name subject to change)? The code would be like:

-- copy paste from manyTill_. It takes a parser p and a finalizer end. It returns the list of 
-- all parsed elements with p and(!) the element parsed with end
manyEndingWith :: MonadPlus m => m a -> m a -> m [a]
manyEndingWith p end = go id
  where
    go f = do
      done <- optional end
      case done of
        Just done' -> return $ f [done']
        Nothing -> do
          x <- p
          go (f . (x :))

This is particulary usefull when parsing the eof. For example in megaparsec this code will hang forever

-- This hangs forever. But I don't know why.
my_parser = (True <$ symbol ";") <|> (True <$ symbol "|") <|> (False <$ eof)
parse (many my_parser) "" ";|"
> hangs forever...

Ideally the last example could return Right [True, True, False], but I think it isn't possible with the current combinators. With the new combinator the above example could be rewritten as

my_parser = (True <$ symbol ";") <|> (True <$ symbol "|")
parse (manyEnding my_parser (False <$ eof)) "" ";|"
> Right [True, True, False]

I know manyTill_ exists but, It returns m ([a], end), forcing you to append end at the end of the list (if a ~ end), which is inefficient for linked lists.

lsmor avatar Jun 19 '23 16:06 lsmor