如何返回接收lambda /函数的匿名函数/ lambda?

时间:2017-03-05 09:16:36

标签: lambda rust closures

可以使用lambda和函数创建一个有序对(在Lisp中),如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的类型?

1 个答案:

答案 0 :(得分:2)

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

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

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

说到这一点:不幸的是,你的返回类型是错误的。你想要的是捕获两个参数xy并返回一个接受另一个闭包的闭包,然后用两个参数调用它。此代码有效:

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

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

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

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

  1. 为什么引用&? Rust中的闭包是Voldemort类型,你只能根据它们实现的特性(例如Fn特征)来讨论它们。通常,您有两种方法可以接受实现特征Foo的任意类型:使用静态分派和单态化(fn bar<T: Foo>(x: T))或作为特征对象和动态分派(fn bar(x: &Foo))。但是,您已经返回了一个特征对象(Box<Fn(...)>),并且特征对象无法使用泛型方法(由于各种原因,它们无法单态化)。这意味着您需要自己接受特征对象,并且由于特征对象未被标注,因此需要隐藏在引用或Box之类的内容。

  2. 封闭装置不会退货!正确,因为这又需要单态化,因为Rust是静态类型的。您展示/链接的示例采用动态类型语言,这些内容不是问题。在Rust,这是一个不同的故事。您可以使用Box<Any>或类似的东西 伪造Rust中的动态类型。但这不是真实的,应该避免。 也许你真的需要它,但也许你也想错误地使用Rust中其他语言的模式,而应该以更生疏的方式思考你的问题; - )< / p>