随笔 - 82,  文章 - 0,  评论 - 95,  阅读 - 22万
1
2
3
4
5
6
7
8
9
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖。如要转贴,必须注明原文网址
 
http://www.cnblogs.com/Colin-Cai/p/10920847.html
 
作者:窗户
 
QQ/微信:6679072
 
E-mail:6679072@qq.com

  本章继续上一章,说明一下这个问题:

  所有的相互递归都可以被转化为一般的递归,从而最终可以用lambda演算来完成。

 

  假设有以下对于f1f2...fn的相互递归:

  f1=F1(f1,f2,...fn)

  f2=F2(f1,f2,...fn)

  ...

  fn=Fn(f1,f2,...fn)

  如果我们定义一个高阶函数(算子)f,满足

  f1=f(1)

  f2=f(2)

  ...

  fn=f(n)

  代入上式,得到

  f(1)=F1(f(1),f(2),...f(n))

  f(2)=F2(f(1),f(2),...f(n))

  ...

  f(n)=Fn(f(1),f(2),...f(n))

  于是以上就是一个对于f的普通递归(f递归到f)。

  从而,我们就知道了,任何递归都可以转化为到自身的普通递归

  

  然而,对于lambda演算,因为自身没有名字,那又如何递归呢?

  我们就用非负整数的最大公约数为例子,还是用Scheme,一步步来。

  我们记gcd(a1,a2,...,an)a1,a2,...,an的最大公约数。

  最大公约数的递归其实很简单:

  (1)gcd(0,a)=a

  (2)如果a不等于0,那么 gcd(a,b)=gcd(b%a,a),此处%是取余数

  (3)gcd(a1,a2,...an)=gcd(a1,gcd(a2,...an))

  

  其中第一条、第二条连续使用就是著名的欧几里得算法,或者称辗转相除法。

  而第三条则用于缩减最大公约数求解的个数,之前我在文章《汉诺塔——各种编程范式的解决》提到,递归可求解的真谛在于缩小问题处理的规模以达到降阶,以上第二、三条则是可以达到降阶的效果。

  于是上述三条再加上gcd()=0gcd(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)=x2的不动点是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

posted on   窗户  阅读(601)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2018-05-24 awk的递归
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示