码迷,mamicode.com
首页 > 其他好文 > 详细

Y combinator

时间:2014-12-10 07:02:06      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   ar   color   sp   on   div   问题   

在lambda演算中,只有两类表达式,一类是函数定义(lambda 表达式),一类是函数应用在参数上。函数定义的形式是匿名的,同时因为没有赋值语句,所以函数它是没有名称可以指代的,没有名称来引用函数,这里自然就遇到一个问题,lambda演算中如何实现递归呢,也就是lambda表达式如何引用自身。Y combinator就是解决匿名函数实现递归的问题的,准确的说是解决匿名函数实现递归的很优雅的方式。下面用scheme语言给出我理解的Y combinator的推导过程。

 

先不去看Y combinator到底是个什么东西,直接考虑,如果对匿名函数递归的实现阶乘

1 (lambda (n)
2     (if (< n 2)
3         1
4         (* n (f (- n 1)))
5         )
6     )

上面代码中写了一个实现阶乘匿名的函数,但是引用了一个不知从哪来的f,f实际上就是匿名函数本身,所以现在就必须想办法把匿名阶乘函数传递给f,匿名函数传递值的唯一办法是通过应用参数实现,好,现在就给这个匿名的阶乘函数添加一个捕获自身的参数

1 (lambda (f)
2     (lambda (n)
3         (if (< n 2)
4             1
5             (* n (f (- n 1)))
6         )
7     )
8 )

现在是添加一个可以捕获自己的参数了,但是还没有捕获自身这个动作,也就是需要应用下自身,自身没有名字怎么办,好吧,把自己再写一遍

 

 1 (lambda (f)
 2     (lambda (n)
 3         (if (< n 2)
 4             1
 5             (* n (f (- n 1)))
 6         )
 7     )
 8 )
 9 (lambda (f)
10     (lambda (n)
11         (if (< n 2)
12             1
13             (* n (f (- n 1)))
14         )    
15    )
16 )

 

仔细看看现在的代码好像还有问题,当“自身”传递给f的时候,f是直接应用了n-1的值,但事实上"自身"是有两个参数的,第一个是f,第二个n,这里f作为“自身”的名字却只应用了一个参数实际上是有问题的,所以(f (- n 1)应该改成((f f) (- n 1))

 1 (lambda (f)
 2     (lambda (n)
 3         (if (< n 2)
 4             1
 5             (* n ((f f) (- n 1)))
 6         )
 7     )
 8 )
 9 (lambda (f)
10     (lambda (n)
11         (if (< n 2)
12             1
13             (* n ((f f) (- n 1)))
14         )    
15    )
16 )

如上,就是一个完整的实现阶乘的递归函数。

 

那Y combinator到底是什么神奇的东西呢,我不用你,其实我依然实现了匿名函数的递归。简单来说Y combinator也是一个匿名函数,也是一个高阶函数,输入是函数,输出是函数,Y combinator的魔力在于应用G后,能生成G的不动点,G的形式如下面代码,

1 (lambda (f)
2     (lambda (args)
3         (    ...
4             (f args)
5              ...
6         )
7     )
8 )

何为不动点,假如存在一个函数F,使得GF=F,F就是G的不动点,而F实际上就是YG,取得不动点,意义在哪,还以阶乘例子说

1 Fact‘ = (lambda (f)
2                 (lambda (n)
3                     (if (< n 2)
4                         1
5                         (* n (f (- n 1)))
6                     )
7                 )
8             )

Fact‘不是阶乘函数,但是我假设有一个叫Fact的阶乘函数,那么Fact’应用到Fact是不是就是我要的阶乘函数,也就是Fact’Fact = Fact,这里就发现了Fact实际上就是Fact‘的不动点,根据之前说的,Y应用Fact’后获取的就是Fact,现在我们知道了Fact‘的形式,Fact的形式也知道了,然后就是想通过YFact’=Fact等式来推出Y的形式

 1 ;将(lambda (x) (x x))应用到Fact可以得到 
 2 (lambda (x) (x x)) Fact 3  =
 4 (lambda (f)
 5     (lambda (n)
 6         (if (< n 2)
 7             1
 8             (* n (f (- n 1)))
 9         )
10     )
11 )
12 (lambda (f)
13     (lambda (n)
14         (if (< n 2)
15             1
16             (* n (f (-n 1)))
17         )    
18    )
19 )

显然(lambda (x) (x x))Fact‘与Fact还是不等价的

 1 ;我们需要先把Fact’的形式:
 2 (lambda (f)
 3     (lambda (n)
 4         (if (< n 2)
 5             1
 6             (* n (f (- n 1)))
 7         )
 8     )
 9 )
10 ;变换成
11 (lambda (f)
12     (lambda (n)
13         (if (< n 2)
14             1
15             (* n ((f f) (- n 1)))
16         )    
17    )
18 )
19 ;然后作用到(lambda (x) (x x))就是完整的Fact了

考虑匿名函数(lambda (g) (lambda (f) (g (f f))))应用到Fact‘,展开便是我们想要的形式了,再综合前述的(lambda (x) (x x))应用便得到Fact

于是完整的过程是(lambda (x) (x x)) ((lambda (g) (lambda (f) (g (f f)))) Fact‘) = Fact,走到这一步还不够,我们要找的Y是能够直接应用Fact’的,

由于(lambda (x) (x x))本质上应用的是(lambda (f) (Fact‘ (f f))),Fact’只要能够传递给(g (f f))中的g,最终就能得到Fact,

现在把参数g放到最外层,得到的lambda表达式就是我们想要的Y

(lambda (g) ((lambda (x) (x x)) (lambda (f) (g (f f)))))

 

参考:http://en.wikipedia.org/wiki/Fixed-point_combinator#Y_combinator

 

 

 

 

Y combinator

标签:style   blog   http   ar   color   sp   on   div   问题   

原文地址:http://www.cnblogs.com/break7/p/4154567.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!