Rust combineでand_then()を使うとき

※本記事の後半（エラー型～注意点）は間違っている部分があるので「[Rust combineでand_then()を使うとき（訂正版）](https://qiita.com/dalance/items/977ddb9556a100d1e737)」も併せてご覧ください。

# はじめに
Rustのパーサコンビネータライブラリ[combine](https://github.com/Marwes/combine)にて`Parser::and_then()`を使おうとしたところ、型合わせが結構大変だったのでその結果を書いておきます。
combineのバージョンは3.8.1です。

# やりたいこと

単に`many1(digit())`で数値を取り出してして`parse::<i32>()`で`i32`に変換して出したい、というだけです。
ここで問題は「`parse::<i32>`が`std::num::ParseIntError`を返す可能性がある」ということで、`Parser::map()`は使えず、結果を`Result`で返せる`Parser::and_then()`を使う必要があります。
すなわち

```rust
fn main() {
    let mut parser = many1(digit()).and_then(|x: String| x.parse::<i32>());
    dbg!(parser.easy_parse("1"));
}
```

という感じです。これは実はドキュメントに載っているコードそのものなので当然通ります。

# `and_then`を使った再利用可能なパーサ

次に、この`many1...`の部分を切り出して再利用可能にしたいと思います。

```rust
fn main() {
    let mut parser = parser(num);
    dbg!(parser.easy_parse("1"));
}

fn num ...
{
    many1(digit()).and_then(|x: String| x.parse::<i32>())
}
```

こんな感じです。問題はこの`fn num`の型は何か、ということです。
Web上でよく出てくるcombineの使用例だと再利用可能なパーサはこんな感じで定義されています。

```rust
fn num<I>(input: &mut I) -> ParseResult<i32, I>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    many1(digit()).and_then(|x: String| x.parse::<i32>()).parse_stream(input)
}
```

これはコンパイルが通らず、以下のようなエラーになります。

```
error[E0277]: the trait bound `<<I as combine::stream::StreamOnce>::Error as combine::error::ParseError<char, <I as combine::stream::StreamOnce>::Range, <I as combine::stream::StreamOnce>::Position>>::StreamError: std::convert::From<std::num::ParseIntError>` is not satisfied
  --> src/main.rs:36:10
   |
36 |         .and_then(|x: String| x.parse::<i32>())
   |          ^^^^^^^^ the trait `std::convert::From<std::num::ParseIntError>` is not implemented for `<<I as combine::stream::StreamOnce>::Error as combine::error::ParseError<char, <I as combine::stream::StreamOnce>::Range, <I as combine::stream::StreamOnce>::Position>>::StreamError`
   |
   = help: consider adding a `where <<I as combine::stream::StreamOnce>::Error as combine::error::ParseError<char, <I as combine::stream::StreamOnce>::Range, <I as combine::stream::StreamOnce>::Position>>::StreamError: std::convert::From<std::num::ParseIntError>` bound
   = note: required because of the requirements on the impl of `std::convert::Into<<<I as combine::stream::StreamOnce>::Error as combine::error::ParseError<char, <I as combine::stream::StreamOnce>::Range, <I as combine::stream::StreamOnce>::Position>>::StreamError>` for `std::num::ParseIntError`

error[E0277]: the trait bound `<<I as combine::stream::StreamOnce>::Error as combine::error::ParseError<char, <I as combine::stream::StreamOnce>::Range, <I as combine::stream::StreamOnce>::Position>>::StreamError: std::convert::From<std::num::ParseIntError>` is not satisfied
  --> src/main.rs:37:10
   |
37 |         .parse_stream(input)
   |          ^^^^^^^^^^^^ the trait `std::convert::From<std::num::ParseIntError>` is not implemented for `<<I as combine::stream::StreamOnce>::Error as combine::error::ParseError<char, <I as combine::stream::StreamOnce>::Range, <I as combine::stream::StreamOnce>::Position>>::StreamError`
   |
   = help: consider adding a `where <<I as combine::stream::StreamOnce>::Error as combine::error::ParseError<char, <I as combine::stream::StreamOnce>::Range, <I as combine::stream::StreamOnce>::Position>>::StreamError: std::convert::From<std::num::ParseIntError>` bound
   = note: required because of the requirements on the impl of `std::convert::Into<<<I as combine::stream::StreamOnce>::Error as combine::error::ParseError<char, <I as combine::stream::StreamOnce>::Range, <I as combine::stream::StreamOnce>::Position>>::StreamError>` for `std::num::ParseIntError`
   = note: required because of the requirements on the impl of `combine::parser::Parser` for `combine::parser::combinator::AndThen<combine::parser::repeat::Many1<std::string::String, combine::parser::char::Digit<I>>, [closure@src/main.rs:36:19: 36:47]>`
```

combineをやっているとコンパイラのエラーメッセージはあてにならないことも多いのですが、今回は妥当なhelpを出してくれています。
このhelp通りにつけると

```rust
fn num<I>(input: &mut I) -> ParseResult<i32, I>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
    <<I as combine::stream::StreamOnce>::Error as combine::error::ParseError<
        char,
        <I as combine::stream::StreamOnce>::Range,
        <I as combine::stream::StreamOnce>::Position,
    >>::StreamError: std::convert::From<std::num::ParseIntError>,
    <I as combine::stream::StreamOnce>::Error: combine::error::ParseError<
        char,
        <I as combine::stream::StreamOnce>::Range,
        <I as combine::stream::StreamOnce>::Position,
    >,
{
    many1(digit())
        .and_then(|x: String| x.parse::<i32>())
        .parse_stream(input)
}
```

となって、これは通ります。さすがに長いので通るギリギリまで削ります。

```rust
fn num<I>(input: &mut I) -> ParseResult<i32, I>
where
    I: Stream<Item = char>,
    I::Error: ParseError<char, I::Range, I::Position>,
    <I::Error as ParseError<char, I::Range, I::Position>>::StreamError: 
        From<ParseIntError>,
{
    many1(digit())
        .and_then(|x: String| x.parse::<i32>())
        .parse_stream(input)
}
```

これくらいなら許容範囲かと思います。
また、`num()`が直接`Parser`を返す実装も可能です。その場合は

```rust
fn main() {
    let mut parser = num();
    dbg!(parser.parse("1"));
}

fn num<I>() -> impl Parser<Input = I, Output = i32>
where
    I: Stream<Item = char>,
    I::Error: ParseError<char, I::Range, I::Position>,
    <I::Error as ParseError<char, I::Range, I::Position>>::StreamError: 
        From<ParseIntError>,
{
    many1(digit()).and_then(|x: String| x.parse::<i32>())
}
```

となります。こちらの方が若干きれいかもしれません。

# （追記）エラー型

エラー型について書き忘れたので追記します。
ここまでの例ではエラー型は`ParseIntError`前提でしたが、実際にはいろいろなエラー型を受けたいですし、単にメッセージだけ出したいことも多いです。なのでもう少し汎用的なエラー型にしておく必要があります。
最終的なエラー型は`combine::easy::Error`になるので以下のような感じで良さそうです。

```rust
fn num<I>(input: &mut I) -> ParseResult<i32, I>
where
    I: Stream<Item = char>,
    I::Error: ParseError<char, I::Range, I::Position>,
    <I::Error as ParseError<char, I::Range, I::Position>>::StreamError: 
        From<::combine::easy::Error<char, I::Range>>,
{
    many1(digit())
        .and_then(|x: String| x.parse::<i32>())
        .parse_stream(input)
}
```

ただ、このままだと`and_then`のところで型推論がうまくいかずアノテーションしてあげる必要があるようです。
また、`ParseIntError`はそのままは渡せなくなったので`into()`で変換してやります。
（`std::error::Error`からの`From`があるので変換できます）

```rust
fn num<I>(input: &mut I) -> ParseResult<i32, I>
where
    I: Stream<Item = char>,
    I::Error: ParseError<char, I::Range, I::Position>,
    <I::Error as ParseError<char, I::Range, I::Position>>::StreamError: 
        From<::combine::easy::Error<char, I::Range>>,
{
    many1(digit())
        .and_then::<_, _, ::combine::easy::Error<char, I::Range>, _>(|x: String|
            x.parse::<i32>().map_err(|x| x.into())
        .parse_stream(input)
}
```

もし何らかのメッセージを渡したい場合はこんな感じです。

```rust
fn num<I>(input: &mut I) -> ParseResult<i32, I>
where
    I: Stream<Item = char>,
    I::Error: ParseError<char, I::Range, I::Position>,
    <I::Error as ParseError<char, I::Range, I::Position>>::StreamError: 
        From<::combine::easy::Error<char, I::Range>>,
{
    many1(digit())
        .and_then::<_, _, ::combine::easy::Error<char, I::Range>, _>(|x: String|
            x.parse::<i32>().map_err(|_| easy::Error::Expected(easy::Info::Borrowed("error!!!")))
        .parse_stream(input)
}
```

# 注意点

`and_then`を使う場合は、（おそらく）`easy_parse`が必須です。
例えば最初の例の`easy_parse`を`parse`に変えただけの

```rust
fn main() {
    let mut parser = many1(digit()).and_then(|x: String| x.parse::<i32>());
    dbg!(parser.parse("1"));
}
```

は通りません。

これは`easy_parse`がエラーとして`combine::stream::easy::ParseError`を返すのに対し、`parse`は`combine::error::ParseError`を返す、という違いによります。
前者は他のエラー型を格納できるように拡張されていますが、後者はパーサ自体のエラーしか格納できないためだと思われます。
はじめ`std::num::ParseIntError`を何とか`combine::error::ParseError`に変換しようと思って結構時間を無駄にしました。

ドキュメントの説明上は`parse`と`easy_parse`の違いはエラーメッセージを出しやすいかどうか、という感じに書かれていたのですが、実際にはこのような違いがあるようです。