遞歸程式
在支持自調用的程式語言中,遞歸可以通過簡單的函式調用來完成,如計算
階乘的程式在數學上可以定義為:
(define (factorial n) (if (= n 0) 1 (* n (factorial (- n 1)))))
不動點組合子
即使一個程式語言不支持自調用,如果在這語言中
函式是
第一類對象(即可以在運行期創建並作為
變數處理),遞歸可以通過
不動點組合子(英語:Fixed-point combinator)來產生。以下Scheme程式沒有用到自調用,但是利用了一個叫做Z 運算元(英語:Z combinator)的不動點組合子,因此同樣能達到遞歸的目的。
(define Z (lambda (f) ((lambda (recur) (f (lambda arg (apply (recur recur) arg)))) (lambda (recur) (f (lambda arg (apply (recur recur) arg)))))))(define fact (Z (lambda (f) (lambda (n) (if (<= n 0) 1 (* n (f (- n 1))))))))
這一程式思路是,既然在這裡函式不能調用其自身,我們可以用 Z 組合子套用(application)這個函式後得到的函式再套用需計算的參數。
尾部遞歸
尾部遞歸是指遞歸函式在調用自身後直接傳回其值,而不對其再加運算。尾部遞歸與
循環是等價的,而且在一些語言(如
Scheme中)可以被最佳化為循環指令。 因此,在這些語言中尾部遞歸不會占用調用堆疊空間。以下
Scheme程式同樣計算一個數字的階乘,但是使用
尾部遞歸:
(define (factorial n) (define (iter product counter) (if (> counter n) product (iter (* counter product) (+ counter 1)))) (iter 1 1))
能夠解決的問題
數據的定義是按遞歸定義的。如Fibonacci函式。
問題解法按遞歸算法實現。如Hanoi問題。
數據的結構形式是按遞歸定義的。如二叉樹、廣義表等。
遞歸數據
數據類型可以通過遞歸來進行定義,比如一個簡單的遞歸定義為
自然數的定義:“一個自然數或等於0,或等於另一個自然數加上1”。
Haskell中可以定義
鍊表為:
data ListOfStrings = EmptyList | Cons String ListOfStrings
這一定義相當於宣告“一個鍊表或是空串列,或是一個鍊表之前加上一個字元串”。可以看出所有鍊表都可以通過這一遞歸定義來達到。