Trait bound error

Hi, in the following code , i don't know why function left is ok while function right compile failed, any suggestions on this is appreciated, thanks.

type ParseResult<'a, Output> = Result<(&'a str, Output), &'a str>;

trait Parser<'a, Output> {
    fn parse(&self, input: &'a str) -> ParseResult<'a, Output>;
}

impl<'a, Output, F> Parser<'a, Output> for F
where
    F: Fn(&'a str) -> ParseResult<'a, Output>,
{
    fn parse(&self, input: &'a str) -> ParseResult<'a, Output> {
        self(input)
    }
}


fn map<'a, P, F, A, B>(parser: P, map_fn: F) -> impl Parser<'a, B>
where
    P: Parser<'a, A>,
    F: Fn(A) -> B,
{
    move |input| parser.parse(input).map(|(i, a)| {
        (i, map_fn(a))
    })
}

fn pair<'a, P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Parser<'a, (R1, R2)>
where
    P1: Parser<'a, R1>,
    P2: Parser<'a, R2>,
{
    move |input| {
        parser1.parse(input).and_then(|(i1, r1)| parser2.parse(i1).map(|(i2, r2)| (i2, (r1, r2))))
    }
}

fn left<'a, P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Parser<'a, R1>
where
    P1: Parser<'a, R1>,
    P2: Parser<'a, R2>,
{
    map(pair(parser1, parser2), |(left, _right)| left)
}

fn right<'a, P1, P2, R1, R2>(parser1: P1, parser2: P2) -> impl Parser<'a, R2>
where
    P1: Parser<'a, R1>,
    P2: Parser<'a, R2>,
{
    move |input| pair(parser1, parser2).parse(input).map(|(i, a)| {
        (i, a.1)
    })
}

Read the compiler error. It says that your closure is not Fn. That can only be the case if it's trying to mutate or move stuff, therefore it can't be called through a shared reference, only by mutable reference or by value (i.e., only once).

The body is not mutating anything, so the error must be accidentally moving something. The only things you are moving (and are not Copy) are the two parsers. Accordingly, if you only use the parsers by reference while calling the pair() combinator, it compiles.

1 Like

Alternatively, move the parsers (by calling pair) before creating the closure, instead of trying to do so every time the closure is called (which is what putting the call in the closure body attempts).

-    move |input| pair(parser1, parser2).parse(input).map(|(i, a)| {
+    let pair = pair(parser1, parser2);
+    move |input| pair.parse(input).map(|(i, a)| {
         (i, a.1)
     })
2 Likes

Yeah, that's probably a better solution.

Thanks for your explanation.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.