Haskell入門(四):遞迴(recursion)
參考教材 :Learn You a Haskell for Great Good (http://learnyouahaskell.com/)
操作環境 :Ubuntu下Linux64位虛擬機器
python入門程式設計, 之後用c++學習資料結構,Haskell萌新。
由於對Haskell中一些詞語的中文翻譯並不瞭解,接下來的內容中重點名詞將有英文和我理解的中文。
Chapter4主要內容
遞迴這一章並沒有特別強調函數語言程式設計與面向物件程式設計的區別。事實上,遞迴更多地是一種思想。
遞迴基本原理
遞迴的主要想法是把一個大問題拆解為同類型的小問題。由於程式應該是有限的,我們要求它能在某種情景下結束執行。這種情景應當是確定的,已知的,不需要再拆解的。在程式設計中它被稱為基礎情景(base case)。
它與數學歸納法類似。我們需要先確定最基礎的情況的結果可解,再確認可以由相對小的情景相對大的情景。在函數語言程式設計裡,可以理解為“將大定義用小定義解決”。
(題外:在這裡推薦《演算法引論》,雖然沒有《演算法導論》那麼大名鼎鼎,但是這本書中對數學歸納法的理解還是很有啟發性的)
斐波那契數列是典型的用遞迴定義的。我們來看看它的實現。

斐波那契數列
上面這一演算法的時間效率並不好,不過我們在這裡只是作為遞迴的例子。
使用遞迴實現函式
在瞭解了遞迴的基本原理後,我們試著用遞迴實現一些基礎功能。
求同型別列表的最大值(maximum)
如果列表長度為0, 丟擲錯誤。如果列表只有一個元素,該元素即為最大值。否則,列表的最大值是列表head與tail部分最大值的較大值。具體實現如圖。

求同型別列表的最大值
返回指定數目的某個元素重複構成的列表(take)
如果指定的數目不是正整數,則返回空列表。否則,返回的是重複次數減一情況下的列表,在開頭加入該元素。

求同型別列表的最大值
中間報錯的部分是由於在使用-時,它不能確定是負數還是減號。加入括號後問題得到解決。
取前幾個元素
如果剩餘列表為空,或者剩餘要取的不是正整數, 則返回空列表。否則,返回的是從tail部分取個數減一後的元素,並在開頭剩餘列表的head。(自己看著覺得很繞,可能看程式碼會好一些?)

取前幾個元素
判斷某個元素是否在列表中出現 (elem)
如果列表為空,返回False.如果元素與列表的head相同,返回True。否則,判斷元素是否在列表的tail部分出現。

判斷某個元素是否在列表中出現
列表元組對應打包(zip)
如果某個列表為空,則返回空。否則,將兩個列表的tail部分元組對應打包後,在開頭加入由兩個head組成的tuple。

列表元組對應打包
如果兩個列表長度不等,則某一個先達到[], 且遞迴部分返回[], 因而返回列表長度以兩個列表中短的為準。
快速排序(quick sort)
遞迴解決快排的想法是:如果列表為空列表或者只有一個元素,那麼它一定是排序好了的。否則,我們先確定一個基準(方便起見,我們取首個元素為基準),將比它大的放在它右邊,比它小的放在它左邊。分別排序左右兩邊,當兩邊排序完畢時,整個列表就排序完畢了。

快速排序
一個元素的情況也可以拆解為空列表的情況,因而第四行可以省略。
非遞迴解決快速排序可以參考百度百科中的程式碼。