In the following sample program, is there any way I could avoid having to define map2?
fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> {
    match a {
        Some(x) => match b {
            Some(y) => Some(f(x, y)),
            None => None,
        },
        None => None,
    }
}
fn main() {
    let a = Some(5);
    let b = Some(10);
    let f = |a, b| {
        a + b
    };
    let res = map2(f, a, b);
    println!("{:?}", res);
    // prints Some(15)
}
For people who also speak Haskell, I guess this question could also be phrased as "Is there any tool we can use instead of liftM2 in Rust?"
I don't believe there's a direct function equivalent to liftM2, but you can combine Option::and_then and Option::map like this:
fn main() {
    let a = Some(5);
    let b = Some(10);
    let f = |a, b| {
        a + b
    };
    println!("{:?}", a.and_then(|a| b.map(|b| f(a, b))));
}
Output:
Some(15)
As of Rust 1.46.0, you can use Option::zip:
fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> {
    match a.zip(b) {
        Some((x, y)) => Some(f(x, y)),
        None => None,
    }
}
This can be combined with Option::map, as shown in other answers:
fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> {
    a.zip(b).map(|(x, y)| f(x, y))
}
I don't know if you can get down to one line (Edit: oh the accepted answer gets it down to one line nicely), but you can avoid the nested match by matching on a tuple:
let a = Some(5);
let b = Some(10);
let f = |a, b| {
    a + b
};
let res = match (a, b) {
    (Some(a), Some(b)) => Some(f(a, b)),
    _ => None,
};
println!("{:?}", res);
// prints Some(15)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With