2017-03-05 68 views
0

它可以創建一個有序對使用Lambda和功能(在Lisp的利弊),如圖Use of lambda for cons/car/cdr definition in SICP如何返回接收lambda/function的匿名函數/ lambda?

它也可以在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) 

當我實現它的鏽,這是一種靜態類型語言:

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的類型?

回答

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是靜態類型的。你展示/鏈接的例子是動態類型語言,類似這樣的東西不是問題。在魯斯特,這是一個不同的故事。你可以假使用Box<Any>或類似的東西在Rust中輸入動態。但這不是真正的習慣,應該避免。也許你真的需要它,但也許也希望正確使用其他語言模式的鏽,而應該認爲你的問題;-)

更生鏽的方法