相互遞歸(2)

  版權申明:本文爲博主窗戶(Colin Cai)原創,歡迎轉帖。如要轉貼,必須註明原文網址

  http://www.cnblogs.com/Colin-Cai/p/10920847.html 

  做者:窗戶

  QQ/微信:6679072

  E-mail:6679072@qq.com

  本章繼續上一章,說明一下這個問題:html

  全部的相互遞歸均可以被轉化爲通常的遞歸,從而最終能夠用lambda演算來完成。算法

 

  假設有如下對於$f_1, f_2, ... f_n$的相互遞歸:sql

  $f_{1} = F_{1}(f_{1}, f_{2}, ... f_{n})$編程

  $f_{2} = F_{2}(f_{1}, f_{2}, ... f_{n})$微信

  ...app

  $f_{n} = F_{n}(f_{1}, f_{2}, ... f_{n})$函數

  若是咱們定義一個高階函數(算子)f,知足spa

  $f_{1} = f(1)$code

  $f_{2} = f(2)$htm

  ...

  $f_{n} = f(n)$

  代入上式,獲得

  $f(1) = F_{1}(f(1), f(2), ... f(n))$

  $f(2) = F_{2}(f(1), f(2), ... f(n))$

  ...

  $f(n) = F_{n}(f(1), f(2), ... f(n))$

  因而以上就是一個對於f的普通遞歸(f遞歸到f)。

  從而,咱們就知道了,任何遞歸均可以轉化爲到自身的普通遞歸

  

  然而,對於lambda演算,由於自身沒有名字,那又如何遞歸呢?

  咱們就用非負整數的最大公約數爲例子,仍是用Scheme,一步步來。

  咱們記$gcd(a_1,a_2, ..., a_n)$是$a_1,a_2, ..., a_n$的最大公約數。

  最大公約數的遞歸其實很簡單:

  (1)$gcd(0, a) = a$

  (2)若是a不等於0,那麼 $gcd(a, b) = gcd(b\%a, a)$,此處%是取餘數

  (3)$gcd(a_1, a_2, ... a_n) = gcd(a_1, gcd(a_2, ... a_n))$

  

  其中第一條、第二條連續使用就是著名的歐幾里得算法,或者稱展轉相除法。

  而第三條則用於縮減最大公約數求解的個數,以前我在文章《漢諾塔——各類編程範式的解決》提到,遞歸可求解的真諦在於縮小問題處理的規模以達到降階,以上第2、三條則是能夠達到降階的效果。

  因而上述三條再加上$gcd() = 0$ 和 $gcd(0) = 0$ 這兩條邊界條件,用Scheme描述遞歸以下:

(define gcd
 (lambda s
  (if (null? s)
   0
   (if (zero? (car s))
    (apply gcd (cdr s))
    (if (null? (cdr s))
     (car s)
     (if (null? (cddr s))
      (gcd (remainder (cadr s) (car s)) (car s))
      (gcd (car s) (apply gcd (cdr s)))
     ))))))

  

  爲了實現匿名遞歸,也就是咱們最終但願在lambda演算中遞歸,咱們須要考慮如下函數

(define g
 (lambda (f)
  (lambda s
   (if (null? s)
    0
    (if (zero? (car s))
     (apply f (cdr s))
     (if (null? (cdr s))
      (car s)
      (if (null? (cddr s))
       (f (remainder (cadr s) (car s)) (car s))
       (f (car s) (apply f (cdr s)))
      )))))))

  咱們此處好好想想,會發現,$g(gcd) = gcd$

  也就是gcd是函數g的不動點。

  其實不動點在其餘函數中同樣存在,好比$f(x) = x^2$的不動點是0,

  只是這裏的函數是高階函數(算子),彷佛挺拗口。

  假若有個函數Y(固然,這個Y也是一個算子)能夠找到算子的不動點,好比使得$g(Y(g)) = Y(g)$,那麼Y(g)就是咱們原本想要實現的gcd,

  因而咱們就經過lambda演算實現了匿名遞歸。 

  那麼這樣的Y存在嗎?

 

  幸運的是,Y函數是存在的,有個學名叫Y combinator,咱們知道美國有個孵化器公司叫這個名字,實際上就是取這個的意義。這個早在Church建立lambda驗算體系的時候就已經發現,並且相當重要,不然就不知道怎麼遞歸了。

  Scheme下,Y combinator能夠以下

(lambda (f)
 ((lambda (g) (g g))
  (lambda (x) (f (lambda s (apply (x x) s))))))

  

  由於gcd函數能夠表示爲Y(g)的形式,

  因而,咱們的gcd就能夠形式以下

(define gcd
 ((lambda (f)
   ((lambda (g) (g g))
    (lambda (x) (f (lambda s (apply (x x) s))))))
  (lambda (f)
   (lambda s
    (if (null? s)
     0
     (if (zero? (car s))
      (apply f (cdr s))
      (if (null? (cdr s))
       (car s)
       (if (null? (cddr s))
        (f (remainder (cadr s) (car s)) (car s))
        (f (car s) (apply f (cdr s)))
       ))))))))

  

  因而,咱們發現gcd的定義過程當中,只用到了lambda演算,從而lambda演算統一了一切!

 

  靠譜嗎?那麼咱們用上述定義的如此詭異的gcd隨便運算一下幾組最大公約數

  (display (gcd 225 150 165))

  獲得

  15

相關文章
相關標籤/搜索