rust-bakery / nom

Rust parser combinator framework
MIT License
9.43k stars 805 forks source link

Add combinator "erasing" output type #1537

Open mwobat opened 2 years ago

mwobat commented 2 years ago

Recently I wanted to write something like this:

fn parser(input: &str) -> IResult<&str, Vec<&str>> {
    map(
        many_till(
            terminated(not_line_ending, line_ending),
            peek(alt((eof, header, modifier))),
        ),
        |(lines, _)| lines,
    )(input)
}

where eof, header and modifier are parsers having different output types.

Unfortunately that doesn't work, because alt only takes parsers having the same output type.

I propose a parser, which returns the unit type if the child parser was succesful. Otherwise just the error.

Let's call it ok here, then I could rewrite the line in question like this:

peek(alt((ok(eof), ok(header), ok(modifier))))

I found a similar combinator in the docs: recognize although it does have an overhead because it returns what the child parser consumed.

Also, please let me know if I missed something 😉

Xiretza commented 2 years ago

I could've sworn there was a void combinator for this, but apparently not. It can be emulated with value((), p), but I agree it'd be a good addition to the library.

mwobat commented 2 years ago

It can be emulated with value((), p)

Oh, I didn't even think of that.

Stargateur commented 2 years ago

You could use the toilet closure eof.map(|_| ())

mwobat commented 2 years ago

You could use the toilet closure eof.map(|_| ())

Yes, but it will be a little longer:

peek(alt((
    eof.map(|_| ()),
    page_header_num.map(|_| ()),
    choice.map(|_| ()),
)))

vs

peek(alt((void(eof), void(page_header_num), void(choice))))

I think the second looks more concise

epage commented 1 year ago

A more Rust centric name for this would be unit since () is the unit type.