版權申明:本文爲博主窗戶(Colin Cai)原創,歡迎轉帖。如要轉貼,必須註明原文網址 http://www.cnblogs.com/Colin-Cai/p/10787636.html 做者:窗戶 QQ/微信:6679072 E-mail:6679072@qq.com
相互遞歸就是多個函數互相定義,最多見的就是兩個函數,好比f和g,f的定義中用到g,而g的定義中用到f。html
相互遞歸同樣有無限遞歸的可能,最簡單的:sql
f:x->g(x)微信
g:x->f(x)閉包
給個最簡單的沒有無限遞歸的例子,判斷一個正整數是否是偶數或者是否是奇數,用C++來描述以下:app
bool is_odd(unsigned x); bool is_even(unsigned x) { if(x == 0u) return true; return is_odd(x-1u); } bool is_odd(unsigned x) { if(x == 0u) return false; return is_even(x-1u); }
以上效率雖然不高(甚至不優化的狀況下,可能會崩棧),可是is_even和is_odd兩個函數畢竟是相互定義的,也是相互遞歸的一個經典例子。函數
Scheme固然同樣支持相互遞歸,r5rs中也是以上述奇偶來作例子。學習
(define (even? x) (if (zero? x) #t (odd? (- x 1)) ) ) (define (odd? x) (if (zero? x) #f (even? (- x 1)) ) )
再給個稍微複雜的例子,Scheme裏的append是個經常使用的函數,它能夠傳入一組列表,獲得這組列表首尾拼接在一塊兒的列表。好比:(append '(1 2 3) '(4 5 6) '(7 8 9))獲得(1 2 3 4 5 6 7 8 9)。測試
每一個人學習Scheme的過程,基本必然伴隨着append函數的自我實現。優化
如下是其中一種實現(固然,append有好幾種不一樣的實現思想):spa
(define (append . lst) (if (null? lst) '() ((apply _append (cdr lst)) (car lst)) ) ) (define (_append . lst) (cond ((null? lst) (lambda (x) x)) ((null? (cdr lst)) (lambda (x) (if (null? x) (car lst) (cons (car x) ((_append (car lst)) (cdr x))) ) ) ) (else (_append (apply append lst))) ) )
固然,_append通常應該實如今append的內部,我這麼寫也是爲了表示的清楚一點。這種寫法是一種相對高級一點的寫法,採用的算子方式,不斷用閉包來傳遞信息,並使用了相互遞歸,append和_append兩個函數互相定義。
固然,一開始就說了,相互遞歸徹底能夠不僅是兩個函數之間的關係,能夠是多個函數之間的關係。
我這裏給個例子,把正整數按照除以3獲得的餘數分爲三類,把整除3的數稱爲type0,把除以3餘1的數稱爲type1,把除以3餘2的數稱爲type2。因而定義三個謂詞函數type0? type1? type2?
如下爲實現:
(define (type0? x) (if (= x 0) #t (type2? (- x 1)) ) ) (define (type1? x) (if (= x 0) #f (type0? (- x 1)) ) ) (define (type2? x) (if (= x 0) #f (type1? (- x 1)) ) )
咱們能夠看到,
type0?的定義中用到type2?
type1?的定義中用到type0?
type2?的定義中用到type1?
測試一下,
(for-each (lambda (x) (display x)(newline)) (map (lambda (x) (cons x (map (lambda (f) (f x)) (list type0? type1? type2?)) ) ) (range 20) ) )
獲得
(0 #t #f #f)
(1 #f #t #f)
(2 #f #f #t)
(3 #t #f #f)
(4 #f #t #f)
(5 #f #f #t)
(6 #t #f #f)
(7 #f #t #f)
(8 #f #f #t)
(9 #t #f #f)
(10 #f #t #f)
(11 #f #f #t)
(12 #t #f #f)
(13 #f #t #f)
(14 #f #f #t)
(15 #t #f #f)
(16 #f #t #f)
(17 #f #f #t)
(18 #t #f #f)
(19 #f #t #f)