函數(shù)式編程是阿隆佐思想的在現(xiàn)實世界中的實現(xiàn)。不過不是全部的lambda演算思想都可以運用到實際中,因lambda演算在設計的時候就不是為了在各種現(xiàn)實世界中的限制下工作的。所以,就像面向?qū)ο蟮木幊趟枷胍粯?,函?shù)式編程只是一系列想法,而不是一套嚴苛的規(guī)定。有很多支持函數(shù)式編程的程序語言,它們之間的具體設計都不完全一樣。在這里我將用Java寫的例子介紹那些被廣泛應用的函數(shù)式編程思想(沒錯,如果你是受虐狂你可以用Java寫出函數(shù)式程序)。在下面的章節(jié)中我會在Java語言的基礎上,做一些修改讓它變成實際可用的函數(shù)式編程語言。那么現(xiàn)在就開始吧。
Lambda演算在最初設計的時候就是為了研究計算相關的問題。所以函數(shù)式編程主要解決的也是計算問題,而出乎意料的是,是用函數(shù)來解決的?。ㄗg者:請理解原作者的苦心,我想他是希望加入一點調(diào)皮的風格以免讀者在中途睡著或是轉(zhuǎn)臺……)。函數(shù)就是函數(shù)式編程中的基礎元素,可以完成幾乎所有的操作,哪怕最簡單的計算,也是用函數(shù)完成的。我們通常理解的變量在函數(shù)式編程中也被函數(shù)代替了:在函數(shù)式編程中變量僅僅代表某個表達式(這樣我們就不用把所有的代碼都寫在同一行里了)。所以我們這里所說的‘變量’是不能被修改的。所有的變量只能被賦一次初值。在Java中就意味著每一個變量都將被聲明為final(如果你用C++,就是const)。在FP中,沒有非final的變量。
final int i = 5;
final int j = i + 3;
既然FP中所有的變量都是final的,可以引出兩個規(guī)定:一是變量前面就沒有必要再加上final這個關鍵字了,二是變量就不能再叫做‘變量’了……于是現(xiàn)在開始對Java做兩個改動:所有Java中聲明的變量默認為final,而且我們把所謂的‘變量’稱為‘符號’。
到現(xiàn)在可能會有人有疑問:這個新創(chuàng)造出來的語言可以用來寫什么有用的復雜一些的程序嗎?畢竟,如果每個符號的值都是不能修改的,那么我們就什么東西都不能改變了!別緊張,這樣的說法不完全正確。阿隆佐在設計lambda演算的時候他并不想要保留狀態(tài)的值以便稍后修改這些值。他更關心的是基于數(shù)據(jù)之上的操作(也就是更容易理解的“計算”)。而且,lambda演算和圖靈機已經(jīng)被證明了是具有同樣能力的系統(tǒng),因此指令式編程能做到的函數(shù)式編程也同樣可以做到。那么,怎樣才能做到呢?
事實上函數(shù)式程序是可以保存狀態(tài)的,只不過它們用的不是變量,而是函數(shù)。狀態(tài)保存在函數(shù)的參數(shù)中,也就是說在棧上。如果你需要保存一個狀態(tài)一段時間并且時不時的修改它,那么你可以編寫一個遞歸函數(shù)。舉個例子,試著寫一個函數(shù),用來反轉(zhuǎn)一個Java的字符串。記住咯,這個程序里的變量都是默認為final的5。
String reverse(String arg) {
if(arg.length == 0) {
return arg;
}
else {
return reverse(arg.substring(1, arg.length)) + arg.substring(0, 1);
}
}
這個方程運行起來會相對慢一些,因為它重復調(diào)用自己6。同時它也會大量的消耗內(nèi)存,因為它會不斷的分配創(chuàng)建內(nèi)存對象。無論如何,它是用函數(shù)式編程思想寫出來的。這時候可能有人要問了,為什么要用這種奇怪的方式編寫程序呢?嘿,我正準備告訴你。
更多建議: