可以使用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
的类型?
答案 0 :(得分:2)
第一个小错误:你在函数体的末尾添加了一个分号。这意味着
Box::new(move |m|m(x,y));
只是一个没有副作用的声明,很像3 + 4;
。删除分号后,您将获得更好的编译器错误,因为现在编译器开始将表达式类型与返回类型连接。
说到这一点:不幸的是,你的返回类型是错误的。你想要的是捕获两个参数x
和y
并返回一个接受另一个闭包的闭包,然后用两个参数调用它。此代码有效:
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));
但我们在这里有两个问题:
为什么引用&
? Rust中的闭包是Voldemort类型,你只能根据它们实现的特性(例如Fn
特征)来讨论它们。通常,您有两种方法可以接受实现特征Foo
的任意类型:使用静态分派和单态化(fn bar<T: Foo>(x: T)
)或作为特征对象和动态分派(fn bar(x: &Foo)
)。但是,您已经返回了一个特征对象(Box<Fn(...)>
),并且特征对象无法使用泛型方法(由于各种原因,它们无法单态化)。这意味着您需要自己接受特征对象,并且由于特征对象未被标注,因此需要隐藏在引用或Box
之类的内容。
封闭装置不会退货!正确,因为这又需要单态化,因为Rust是静态类型的。您展示/链接的示例采用动态类型语言,这些内容不是问题。在Rust,这是一个不同的故事。您可以使用Box<Any>
或类似的东西 伪造Rust中的动态类型。但这不是真实的,应该避免。 也许你真的需要它,但也许你也想错误地使用Rust中其他语言的模式,而应该以更生疏的方式思考你的问题; - )< / p>