Bimap for Result

I'm new to Rust, coming from a functional Scala background. I noticed in a few places in my code when dealing with Result types that I'm calling map and map_err immediately after, when I want to return a Result after applying the appropriate function (depending on whether the result is Ok or `Err'). In Scala, we'd call this 'bimap'.

I don't see such a function defined on Result - .map_or_else is close, but it wants to return a non-result type. Can I define something like it?

I tried to sketch out something like it:

use std::ops::FnOnce;

trait ResultOps<T, E> {
    fn bi_map<U, A, B, D: FnOnce(E) -> B, F: FnOnce(T) -> A>(self, l: D, r: F) -> Result<A, B>;
}

impl ResultOps<T, E> for Result<T, E> {
    fn bi_map<U, A, B, D: FnOnce(E) -> B, F: FnOnce(T) -> A>(self, l: D, r: F) -> Result<A, B> {
        match self {
            Ok(t) => Ok(r(t)),
            Err(e) => Err(l(e)),
        }
    }
}

Am I close? The compiler is happy with my trait, but can't find T or E in my implementation:

cannot find type `T` in this scope

not found in this scope

Very close!

You need to tell rust that you're going to use a generic type:

impl<T,E> ResultOps<T, E> for Result<T, E> 

Also the U generic looks to be unneeded.

1 Like

You're right, thanks! This seems to compile and it works in my code:

use std::ops::FnOnce;

pub trait ResultOps<T, E> {
    fn bi_map<A, B, D: FnOnce(E) -> B, F: FnOnce(T) -> A>(self, l: D, r: F) -> Result<A, B>;
}

impl<T, E> ResultOps<T, E> for Result<T, E> {
    fn bi_map<A, B, D: FnOnce(E) -> B, F: FnOnce(T) -> A>(self, l: D, r: F) -> Result<A, B> {
        match self {
            Ok(t) => Ok(r(t)),
            Err(e) => Err(l(e)),
        }
    }
}

As for why it's like this: It's possible to make a non-generic impl block. So you can do

impl ResultOps<PathBuf, String> for Result<PathBuf, String> {

at which point you don't want those to be the names of generic parameters.

(Now, obviously you don't want that in this particular case, but that's why the declaration is needed for the generic types.)

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.