递归。哦,递归。 递归在计算机科学中的重要性不言而喻。 递归就像女人,即令人烦恼,又无法抛弃。
先上个例子,这个例子里的函数double输入一个非负整数
现在的问题是,这个递归函数在我们的语言里没法直接定义。 我说的直接定义是指像这个用let表达式:
获得递归的一个关键是如何在函数体中找到自己(结合一开始的比喻,这句话好像蕴含了其他意义深远的意思)。 一个简单的方法是在double上增加一个参数(一般就是第一个参数),把自己传入参数。 把这个修改后的函数叫做mkdouble1吧。 先不考虑mkdouble1的定义,先观察mkdouble1的行为。 因为调用mkdouble1要把自己作为第一个参数传入,所以调用递归函数应该这样写:
现在来考虑mkdouble1的定义。 在double上增加一个参数
1
2
3
4
5
6
7 |
‘(let double (( lambda
v (v v)) ( lambda
f ( lambda
n ( if
(iszero n) 0 ( + 2 ((f f) ( - n 1 ))))))) (double 4 )) >> 8 |
这一小节比较理论,知道个思路就行了。所以我就随便写写。 好学的人可以自己查资料(Programming Languages and Lambda Calculi, The Little Schemer)。
mkdouble1并不能让人很满意,因为它不优雅(都是时臣的错)。 mkdouble1递归调用的地方用的是
Y组合子可以用来构造递归函数。 不过上面的定义在call-by-value的调用方式下会进入无限循环。 具体原因就不讲了,只讲结论:问题出在v
测试一下。 Call-by-value的测试:
1
2
3
4
5
6
7
8
9
10
11 |
‘(let Y ( lambda
x (( lambda
v (v v)) ( lambda
f (x ( lambda
u ((f f) u)))))) (let mkdouble ( lambda
f ( lambda
n ( if
(iszero n) 0 ( +
2 (f ( - n 1 )))))) ((Y mkdouble) 4 ))) >> 8 |
Call-by-name的测试:
1
2
3
4
5
6
7
8
9
10
11 |
‘(let Y ( lambda
x (( lambda
v (v v)) ( lambda
f (x (f f))))) (let mkdouble ( lambda
f ( lambda
n ( if
(iszero n) 0 ( +
2 (f ( - n 1 )))))) ((Y mkdouble) 4 ))) >> 8 |
简单易懂的程序语言入门小册子(4):基于文本替换的解释器,递归,如何构造递归函数,Y组合子,布布扣,bubuko.com
简单易懂的程序语言入门小册子(4):基于文本替换的解释器,递归,如何构造递归函数,Y组合子
原文:http://www.cnblogs.com/skabyy/p/3677836.html