Let's say I have a tuple of things that I want to pass to a function, is there a way to do that without explicitly unwrapping the elements of the tuple?
In other languages, such as Scala and Haskell this would be called untupling. A common case is that I have extracted optional values from somewhere and I want to map over the scenario where they all exist (this could also be accomplished with a match but I find a zip can be cleaner for this simple case, which would result in nested tuples if we extended it to higher arities, so zip2/zip3/zipN etc often exist)
let oa = get_optional_thing("a", map_thing);
let ob = get_optional_thing("b", map_thing);
oa.zip(ob).map( |(a, b)| MyThing::new(a, b))
in this last line I would prefer to be able to write
oa.zip(ob).map(MyThing::new)
is that possible in any way without me manually creating a function that takes the tuple as a parameter?
(we could also imagine doing it more like (oa, ob).apply2(MyThing::new) if we were to copy the Haskell Applicative esque suite of functions)
Though @paramagnetic's answer is fine, I'd like to add another solution. You can create an extention trait, which will allow you to pass your mapping function directly, without wrapping it in untuple:
trait UntupleMap2Ext<T1, T2> {
fn untuple_map2<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T1, T2) -> U;
}
impl<T1, T2> UntupleMap2Ext<T1, T2> for Option<(T1, T2)> {
fn untuple_map2<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T1, T2) -> U,
{
self.map(|(t1, t2)| f(t1, t2))
}
}
fn main() {
let x = Some(3);
let y = Some(4);
let f = |a, b| a + b;
assert_eq!(x.zip(y).untuple_map2(f), Some(7));
}
The macro-based approach has the drawback that all arguments need to be written out explicitly and the second requires the argument as an immediate input.
Unfortunately I could not get an identical version as @paramagnetic to work for higher-order tuples by using a trait imp as in my second approach.