rust-itertools / itertools

Extra iterator adaptors, iterator methods, free functions, and macros.
https://docs.rs/itertools/
Apache License 2.0
2.77k stars 309 forks source link

cons_tuples: (A, (B, C)) -> (A, B, C) doesn't work. Would it be possible to generalize cons_tuples to allow this? #982

Open zekefast opened 3 months ago

zekefast commented 3 months ago

Example from documentation ((A, B), C) -> (A, B, C) works pretty well!

use itertools::*;

fn main() {
    let one_two = std::iter::once((1, 2));
    let three = std::iter::once(3);

    dbg!(cons_tuples(izip!(one_two, three)).collect::<Vec<_>>());

}

but when order of tuples changes the code starts fall apart.

use itertools::*;

fn main() {
    let one_two = std::iter::once((1, 2));
    let three = std::iter::once(3);

    dbg!(cons_tuples(izip!(three, one_two)).collect::<Vec<_>>());

}

with the following error

error[E0599]: `ConsTuples<std::iter::Zip<std::iter::Once<{integer}>, std::iter::Once<({integer}, {integer})>>, ({integer}, ({integer}, {integer}))>` is not an iterator
  --> src/main.rs:7:45
   |
7  |     dbg!(cons_tuples(izip!(three, one_two)).collect::<Vec<_>>());
   |                                             ^^^^^^^ `ConsTuples<std::iter::Zip<std::iter::Once<{integer}>, std::iter::Once<({integer}, {integer})>>, ({integer}, ({integer}, {integer}))>` is not an iterator
   |
  ::: /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/itertools-0.13.0/src/cons_tuples_impl.rs:35:1
   |
35 | pub struct ConsTuples<I, J>
   | --------------------------- doesn't satisfy `_: Iterator`
   |
   = note: the full name for the type has been written to '/playground/target/debug/deps/playground-a1c33eced4cba996.long-type-36508219185732840.txt'
   = note: consider using `--verbose` to print the full type name to the console
   = note: the following trait bounds were not satisfied:
           `ConsTuples<std::iter::Zip<std::iter::Once<{integer}>, std::iter::Once<({integer}, {integer})>>, ({integer}, ({integer}, {integer}))>: Iterator`
           which is required by `&mut ConsTuples<std::iter::Zip<std::iter::Once<{integer}>, std::iter::Once<({integer}, {integer})>>, ({integer}, ({integer}, {integer}))>: Iterator`

For more information about this error, try `rustc --explain E0599`.

Would it possible to make it work for different structure of the tuples?

If you have some suggestions on implementations, I'm willing to make a PR.

And big thank you to all maintainers for the great library!!!

scottmcm commented 3 months ago

Hmm, curious. By the name cons I'd have expected it to only support (a, (b, (c, d))) order, since that want consing creates in lisp.

zekefast commented 3 months ago

Hmm, curious. By the name cons I'd have expected it to only support (a, (b, (c, d))) order, since that want consing creates in lisp.

Yeah, you are right. Probably it would be better to create some other functions to do that.

zekefast commented 3 months ago

@scottmcm What do you thing about implementing flatten for nested tuples?

phimuemue commented 3 months ago

Just my two cents: cons_tuples seems (yet again) to be a "special-case map", and with these I increasingly think we should not offer them (or at least implement it as MapSpecialCase). My argument: Why should concatenating tuples be tied to iterators? - Tuples originate elsewhere, too.

I imagine that a dedicated fn cons_tuples((A1, A2,...), (B1, B2,...))->(A1, A2,..., B1, B2,...) would be the way to go, and if users want to use it with iterators, they can use iter.map(cons_tuples).

As for flatten: Might be a candidate for tupletools, but I think fleshing out the details for it begs some more questions, i.e. how to deal with the exponentially (?) many combinations of tuple nestings?