问题描述
有没有办法提升一个简单的函数,就像这样
fn add(a:i32, b:i32) -> i32 {a+b}
对Option
(或任何其他一元类型)进行操作,类似于在Haskell
中使用Applicative
我知道此解决方案:
pub fn add(a: Option<i32>, b: Option<i32>) -> Option<i32> {
Some(a? + b?)
}
但这需要我实际编写一个单独的函数,该函数与Option
紧密耦合,而我想要的是能够将任意函数提升为任意一元类型,或者以某种其他方式重复使用具有一元类型的参数和返回值的简单类型上操作的函数
// something like this
let func = Option::lift2(add) //example, not working code
我显然在想Haskell
,也许Rust
中有更多惯用的方法
推荐答案
您可以从以下内容开始:
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,
}
}
}
或者,简而言之:
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?))
}
请注意,FnMut
和FnOnce
可能也需要类似的内容。
此外,以上仍然绑定到Option
,而不是一般的一元对象,这在Rust中模拟起来相当麻烦(如果可能的话)。