如何在 Rust 中实现多级柯里化函数?

Posted

技术标签:

【中文标题】如何在 Rust 中实现多级柯里化函数?【英文标题】:How to implement a multi-level currying function in Rust? 【发布时间】:2021-01-08 07:12:18 【问题描述】:

我尝试实现一个类似于Functional Programming Jargon in Rust的柯里化函数:

fn add_origin(x: i32) -> impl Fn(i32) -> i32 
    return move |y| 
        x + y
    ;


fn main() 
    let add5 = add_origin(5);
    println!("Call closure: ", add5(6));

这可行,但如果我更深一层:

fn add(x: i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 
    return move |y: i32| 
        return move |z: i32| 
            x + y + z
        
    ;


fn main() 
    let add5 = add(5);
    let add5_10 = add5(10);
    println!("Call closure: ", add5_10(6));

编译器不接受并告诉我:

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
 --> src/main.rs:7:35
  |
7 | fn add(x: i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 
  |                                   ^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

为什么不允许这样做? Rust 中是否有更好的替代方案?

【问题讨论】:

我找到了解决办法:play.rust-lang.org/… 【参考方案1】:

impl Trait 语法只能用于函数签名的参数位置或返回位置。这两个都很好:

fn takes_fn(fn_arg: impl Fn(i32) -> i32) 

fn returns_fn() -> impl Fn(i32) -> i32 
  |x| x

但是这些都不起作用:

fn takes_fn(fn_arg: impl Fn(i32) -> impl Fn(i32) -> i32) 

fn returns_fn() -> impl Fn(i32) -> impl Fn(i32) -> i32 
  |x| x

因为第二个嵌套的impl Trait 不再位于参数或返回位置,但现在是参数或返回类型签名的一部分,这不是允许的位置。基本上,多个嵌套的 impl Traits 将永远无法工作,无论您将它们放在哪里,您都会得到相同的编译错误。

好消息是这不会阻止你完成你想要完成的事情,因为impl Trait 只是语法糖,它的使用是可选的。在您的特定示例中,我们可以使用盒装特征对象来返回您的柯里化函数。

fn add(x: i32) -> impl Fn(i32) -> Box<dyn Fn(i32) -> i32> 
    move |y: i32| 
        Box::new(move |z: i32| 
            x + y + z
        )
    


fn main() 
    let add5 = add(5);
    let add5_10 = add5(10);
    println!("Call closure: ", add5_10(6)); // prints "Call closure: 21"

playground

另见:

What does `impl` mean when used as the argument type or return type of a function? What makes `impl Trait` as an argument "universal" and as a return value "existential"?

【讨论】:

以上是关于如何在 Rust 中实现多级柯里化函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在javascript中实现分层多级数据表?

如何在 Bootstrap v4.1 中实现多级下拉菜单? [复制]

如何在柯里化函数中推断泛型?

如何要求泛型类型在泛型函数中实现 Add、Sub、Mul 或 Div 之类的操作?

浅谈函数柯里化

使用 r2d2 在 rust/diesel 应用程序中实现连接池