程序设计最有趣的地方可能就在于递归了,递归可以通过另一种方式实现重复,实现循环。就像两面镜子,相互对望,镜子中的镜子永远没有止境。但递归有个缺点就是非常容易栈溢出,如果没有栈溢出,又没有设置递归终止条件,那么递归就像个黑洞一样,循环自己无边无尽。为防止溢出,多数程序设计语言都有尾递归的表达,但真正支持尾递归的需要进行尾递归优化,似乎只有C语言和lisp语言行。今天再提一种程序语言---forth,可能接近尾递归吧。
我不知道forth的这种递归方法是不是就是尾递归,我称其为类尾递归。
如从1+2+3+...+n=? 当n=100时,?=5050。循环和迭代就不再循环描述了。
这里的forth代码实现如下:
: more
2dup + nip swap 1+ dup -rot
100 <= if recurse then ;
1 0 more
可如果当n=10000时,马上就栈溢出了。
forth有着得天独厚的返回栈操作方法,只需管理好返回栈中的新增的单词地址就可以了。简单点就是不要让返回栈中的地址值随着递归单词的增加而增加,那么只要用一个rdrop就可以了。
代码如下:
: more
2dup + nip swap 1+ dup -rot
100 <= if rdrop recurse then ;
1 0 more
似乎是对了,但该递归单词后面的程序竟然没有被执行,那说明返回栈删除这种方式不对?
forth对开发者是很透明的,返回栈可以自己用rp@和rp0来观察值,我发现第一个返回栈中的值不对随后一个也不变,而当大于第二个栈中值时就发生地址增加。
修改代码如下:
: more1 2dup + nip swap 1+ dup -rot
1000000 <= if dup 2 >= if rdrop then recurse then ;
1 0 more1
结果显示500000500000 。
这就是Forth的类尾递归,同时对forth学习探寻的漫漫苦学之路也开始了,无穷无尽,直到世界的尽头。