rfcs
rfcs copied to clipboard
Support flattening of tuples
I believe that there should be some way of flattening a tuple. The most common reason is probably from a macro or within one that calls a function that returns a tuple but the result of the macro is a flattened tuple.
Example:
(5, (10, "Hello World")) -> (5, 10, "Hello World")
This is currently not possible I believe
It would be generally nice to have more support for structural transformations. Variadic generics are going to help for sure. I think that once the language itself is powerful enough, these kinds of things can be done in 3rd party libs. Check Frunk's HList for inspiration.
Yes I know of HList but native rust has tuple destruction
let (x, y, z) = (5, 10, "Hello World");
However, something like HList cannot support that. I am also not talking about indexing into a tuple.
What kind of situations would you use flattening tuples? I have not used nested tuples yet, but if I did, I would consider refactoring (nested tuples may be confusing)
This would be mostly useful in the creation of macros. Say that you have a function that returns a tuple. And you want to create a macro that accepts multiple versions of the input but still outputs in a flat tuple.
This is desirable because of tuple destructoring.
It’s easy to solve with a type operator, but with (,)
, I’m not sure…
I implemented this with specialization and auto trait.
See https://docs.rs/flatten/*/flatten/
How deeply nested it is doesn't matter and empty unit tuple ()
is removed.
(this is same as python)
(1, (2, 3), (4, ((5,),), ), 6).flatten() == (1, 2, 3, 4, 5, 6)
Edit: more description
@kdy1 Perhaps this can be merged into frunk eventually? Might be good to have a larger crate with these sorts of facilities.
@Centril frunk seems like a library for stable rust. If using cargo feature is ok, I will be happy to merge it into frunk.
Perhaps if we choose to pursue a dedicated syntax, this could work:
let a = 5;
let b = (10, "Hello World");
assert_eq!((a, ..b), (5, 10, "Hello World"));
..x
already means RangeTo { end: x }
. Try another symbol :wink:
I second @Nokel81 request. This would also be very useful for working with Option
s and zip
chains
let a_opt = Some(1)
let b_opt = Some(2)
let c_opt = Some(3)
if let ((a, b), c) = a_opt.zip(b_opt).zip(c_opt)
{
some_fn(a, b, c);
}
I'm also in need of this feature in this kind of context:
foo0
.and(foo1)
.and(foo2)
// ... etc
where each and
merge result, this result in (((a, b), c), d)
not very user friendly. Thus it's not blocking at all my project.
Well ... the dedicated syntax, how about this:
let a = 5;
let b = (10, "Hello World");
assert_eq!((a, ...b), (5, 10, "Hello World"));
I mean ...x
; or, ....x
... 🤔 (maybe not a good idea ...)
It could be useful in case if you have a frunk's hlist of a single type, then convert it to nested tuple, flatten tuple and then to [T; _].
Unpopular and probably very bad syntax suggestion: jq can flatten lists into iterators using []
[1, 2, 3] |
[0, .[]] # produces [0, 1, 2, 3]
EIther way, I think the exact syntax is not really a concern here. We could start with less fancy syntax using whatever verbose primitives we could offer (just like try!(x)
before x?
), either using macros or magical traits or whatever and just progress on a concise syntax later.