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