【问题标题】:How to return an anonymous function/lambda that receives a lambda/function?如何返回接收 lambda/函数的匿名函数/lambda?
【发布时间】:2017-07-25 04:42:21
【问题描述】:

可以使用 lambda 和函数创建有序对(Lisp 中的 cons),如 Use of lambda for cons/car/cdr definition in SICP 所示

它也适用于 Python:

def cons(x,y):
    return lambda m:m(x,y)
def car(z):
    return z(lambda x, y: x)
def cdr(z):
    return z(lambda x, y: y)

当我在 Rust(一种静态类型语言)中实现它时:

fn cons(x: i32, y: i32) -> Box<Fn() -> Fn(i32, i32)> {
    Box::new(move |m| m(x, y));
}

它显示错误:

error: the type of this value must be known in this context
 --> src/main.rs:2:23
  |
2 |     Box::new(move |m| m(x, y));
  |                       ^^^^^^^

error[E0308]: mismatched types
 --> src/main.rs:1:54
  |
1 |   fn cons(x: i32, y: i32) -> Box<Fn() -> Fn(i32, i32)> {
  |  ______________________________________________________^ starting here...
2 | |     Box::new(move |m| m(x, y));
3 | | }
  | |_^ ...ending here: expected box, found ()
  |
  = note: expected type `Box<std::ops::Fn() -> std::ops::Fn(i32, i32) + 'static + 'static>`
  = note:    found type `()`

如何定义m的类型?

【问题讨论】:

    标签: lambda rust closures


    【解决方案1】:

    第一个小错误:您在函数体的末尾添加了一个分号。这意味着

    Box::new(move |m|m(x,y));
    

    只是一个没有副作用的声明,很像3 + 4;。当你删除分号时,你会得到一个更好的编译器错误,因为现在编译器开始连接你的表达式类型和返回类型。

    说到这里:很遗憾,您的返回类型是错误的。您想要的是捕获两个参数 x 和 y 并返回一个闭包,该闭包接受 another 闭包,然后使用这两个参数调用该闭包。此代码有效:

    fn cons(x: i32, y: i32) ->  Box<Fn(&Fn(i32, i32))> {
        Box::new(move |m| m(x, y))
    }
    

    如您所见,返回的闭包类型为:Fn(&amp;Fn(i32, i32))。一个接受 另一个 闭包作为参数的闭包。你可以这样使用它:

    let fun = cons(3, 7);
    fun(&|x, y| println!("{}", x));
    

    但是我们这里有两个问题:

    1. 为什么引用&amp;? Rust 中的闭包是 Voldemort 类型,您只能根据它们实现的特征(例如 Fn 特征)来谈论它们。通常,您有两种方法来接受实现 trait Foo 的任意类型:使用静态分派和单态化 (fn bar&lt;T: Foo&gt;(x: T)) 或作为 trait 对象和动态分派 (fn bar(x: &amp;Foo))。但是,您已经返回了一个 trait 对象 (Box&lt;Fn(...)&gt;),并且 trait 对象不能有泛型方法(由于各种原因它们不能被单态化)。这意味着您需要自己接受 trait 对象,并且由于 trait 对象没有大小,它们需要隐藏在引用或 Box 之类的东西后面。

    2. 闭包不会返回任何东西!正确,因为这又需要单态化,因为 Rust 是静态类型的。您显示/链接的示例使用动态类型语言,这样的事情不是问题。在 Rust 中,情况就不同了。你可以通过使用Box&lt;Any&gt; 或类似的东西来伪造Rust 中的动态类型。但这并不是真正的惯用语,应该避免。 也许你真的需要它,但是也许你也想在 Rust 中错误地使用其他语言的模式,而应该以更生疏的方式思考你的问题 ;-)

    【讨论】:

      猜你喜欢
      • 2019-09-12
      • 2020-04-25
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 2015-08-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多