Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested impl Trait for higher-order functions #76410

Open
nwtgck opened this issue Sep 6, 2020 · 3 comments
Open

Nested impl Trait for higher-order functions #76410

nwtgck opened this issue Sep 6, 2020 · 3 comments
Labels
A-impl-trait Area: impl Trait. Universally / existentially quantified anonymous types with static dispatch. C-feature-request Category: A feature request, i.e: not implemented / a PR.

Comments

@nwtgck
Copy link

nwtgck commented Sep 6, 2020

Hi!

It will be nice to use impl Trait with higher-order functions like the following. But it occurs a compile error at impl Iterator<Item=u32>.

fn f1<F: FnMut(u32) -> u32>(a: u32) -> impl FnOnce(F) -> impl Iterator<Item=u32> /* <- compile error! */ {
    move |f: F| {
        (0..a).map(f)
    }
}

fn main() {
    let iter = f1(10)(|b| b * 2);
    for x in iter {
        println!("{:}", x);
    }
}

Nested impl Trait: https://doc.rust-lang.org/error-index.html#E0666

expected behavior/work around

Here is an expected behavior and a work around. We need to write the type explicitly like std::iter::Map<std::ops::Range<u32>, F> instead of impl Iterator<Item=u32>.

fn f1_with_explicit_type<F: FnMut(u32) -> u32>(a: u32) -> impl FnOnce(F) -> std::iter::Map<std::ops::Range<u32>, F> {
    move |f: F| {
        (0..a).map(f)
    }
}

fn main() {
    let iter = f1_with_explicit_type(10)(|b| b * 2);
    for x in iter {
        println!("{:}", x);
    }
}

Rust Playground

The output should be the following.

0
2
4
6
8
10
12
14
16
18

It will be harder to write and read the return type when we append other methods after the .map(f).

@jyn514 jyn514 added A-impl-trait Area: impl Trait. Universally / existentially quantified anonymous types with static dispatch. C-feature-request Category: A feature request, i.e: not implemented / a PR. labels Sep 6, 2020
@toothbrush7777777
Copy link

toothbrush7777777 commented Sep 6, 2020

If you read the page you linked (https://doc.rust-lang.org/error-index.html#E0666), you need to define the type as a named generic parameter:

fn f1<F: FnMut(u32) -> u32, T: impl Iterator<Item=u32>>(a: u32) -> impl FnOnce(F) -> T {
    move |f: F| {
        (0..a).map(f)
    }
}

fn main() {
    let iter = f1(10)(|b| b * 2);
    for x in iter {
        println!("{:}", x);
    }
}

@nwtgck
Copy link
Author

nwtgck commented Sep 6, 2020

@toothbrush7777777 Actually, I did. I think you mean the following, not T: impl Iterator...

fn f1_with_named_generic<F: FnMut(u32) -> u32, T: Iterator<Item=u32>>(a: u32) -> impl FnOnce(F) -> T {
    move |f: F| {
        (0..a).map(f)
    }
}

Then, we will have a compile error as follows. So, I don't think a named generic parameter works...

error[E0308]: mismatched types
  --> src/main.rs:31:9
   |
29 | fn f1_with_named_generic<F: FnMut(u32) -> u32, T: Iterator<Item=u32>>(a: u32) -> impl FnOnce(F) -> T {
   |                                                - this type parameter
30 |     move |f: F| {
31 |         (0..a).map(f)
   |         ^^^^^^^^^^^^^ expected type parameter `T`, found struct `std::iter::Map`
   |
   = note: expected type parameter `T`
                      found struct `std::iter::Map<std::ops::Range<u32>, F>`

@nwtgck
Copy link
Author

nwtgck commented Sep 6, 2020

Another work around

Here is another work around with type_alias_impl_trait in Nightly Rust.

#![feature(type_alias_impl_trait)]

type IterU32<T> = impl Iterator<Item=u32>;

fn f1_with_impl_trait_alias<F: FnMut(u32) -> u32>(a: u32) -> impl FnOnce(F) -> IterU32<F> {
    move |f: F| {
        (0..a).map(f)
    }
}

fn main() {
    let iter = f1_with_impl_trait_alias(10)(|b| b * 2);
    for x in iter {
        println!("{:}", x);
    }
}

Rust Playground

ref: https://stackoverflow.com/a/39490692/2885946

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-impl-trait Area: impl Trait. Universally / existentially quantified anonymous types with static dispatch. C-feature-request Category: A feature request, i.e: not implemented / a PR.
Projects
None yet
Development

No branches or pull requests

3 participants