Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lifting function to Option

Is there a way to lift a simple function, like this

fn add(a:i32, b:i32) -> i32 {a+b}

to operate on Option (or any other monadic type), similar to how one would use Applicative in Haskell

I'm aware of this solution:

pub fn add(a: Option<i32>, b: Option<i32>) -> Option<i32> {
  Some(a? + b?)
}

but that requires me to actually write a separate function, that is tightly coupled with Option, whereas what I want is to be able to lift an arbitrary function to an arbitrary monadic type, or some other way to re-use functions operating on simple types with arguments and return values of monadic types

// something like this
let func = Option::lift2(add) //example, not working code                         

I'm obviously thinking Haskell, maybe there's more idiomatic way of doing this in Rust

like image 785
dark_ruby Avatar asked Mar 23 '26 12:03

dark_ruby


1 Answers

You could start out with this:

fn lift<A, B, C>(f: impl Fn(A, B)->C) -> impl Fn(Option<A>, Option<B>)->Option<C> {
    move |oa, ob| {
        match (oa, ob) {
            (Some(a), Some(b)) => Some(f(a,b)),
            _ => None,
        }
    }
}

Or, to make it shorter:

fn lift<A, B, C>(f: impl Fn(A, B)->C) -> impl Fn(Option<A>, Option<B>)->Option<C> {
    move |a, b| Some(f(a?, b?))
}

Beware that you would possibly need similar things for FnMut and FnOnce, too.

Moreover, the above is still bound to Option, and not generic over monadic things in general, which is afaik quite cumbersome to simulate in Rust (if possible at all).

like image 95
phimuemue Avatar answered Mar 26 '26 14:03

phimuemue