版权申明:本文为博主窗户(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