erlang 尾递归
来源:互联网 发布:java 输出参数 out 编辑:程序博客网 时间:2024/06/02 15:44
前面的博文中说过递归和尾递归的区别.在ERLANG中,到处存在的都是递归,或者说我们实现的时候优先考虑的应该是尾递归.
那应该如何去写好尾递归呢?
递归,除去List Comprehensions,在ERLANG中唯一存在的循环结构就是递归了.所以在ERLANG中递归是需要重点掌握的概念,
当然,正确写好ERLANG递归程序也不是简单的事情.
这几天大量搜索了一下ERLANG关于递归程序写法,就在这总结一下.
Example One:
- | %% @Func Duplicate_Forest
- | %% @Breif 给定一个参数,复制N次返回一个List
- | Duplicate_Forest(0,_) ->
- | [];
- | Duplicate_Forest(N,Term) when N > 0 ->
- | [Term|Duplicate_Forest(N-1,Term)].
上面给的Example One是普通的递归写法,程序算是完成了,但是在ERLANG世界里,这样子的程序可是不合格的.
所以需要将这段代码改成尾递归的形式才算是合格.
Tail Recursion实现:
- | %% @Func Tail_Duplicate_Forest
- | %% @Breif 给定一个参数,复制N次返回一个List(尾递归实现)
- | Tail_Duplicate_Forest(N,Term) ->
- | Tail_Duplicate_Forest(N,Term,[]).
- | Tail_Duplicate_Forest(0,_,List) ->
- | List;
- | Tail_Duplicate_Forest(N,Term,List) when N > 0 ->
- | Tail_Duplicate_Forest(N-1, Term, [Term|List]).
前一篇博文中说过,尾递归的实现需要借助辅助变量,是对递归的"尾"调用的实现,结果都保存在形参中.
所在在上面的尾递归的实现中,添加了第三个辅助变量"List",形参List一直被用来传递上一次迭代调用的结果,作为下一次迭代调用的形参.
递归需要递归的终止条件.而该片段代码的终止条件是N的值为0,所以只需要无条件返回调用结果,而结果就保存在我们的辅助变量List中.
而我们在程序的参数要求方面是两个:N/Term,所以需要辅助变量初始化为[].
Example Two:
- | %% @Func Reverse_Forest
- | %% @Breif 倒转List中的Element
- | Reverse_Forest([]) ->
- | [];
- | Reverse_Forest([H|T]) ->
- | Reverse_Forest(T)++[H].
这同样是普通递归实现的一个小函数,函数的功能是实现对List的元素倒置.同样,需要将其改为合格的ERLANG尾递归程序.
Tail Recursion实现:
首先记住我们需要的参数只有一个,但是需要一个辅助变量,所以第一个函数分支是比较好些的.
- | Tail_Recursion_Forest(List) ->
- | Tail_Recursion_Forest(List,[]);
下面需要的是对参数的检查,如果List是[],该怎么处理.
- | Tail_Recursion_Forest([],Acc) -> Acc;
最后就应该是尾递归的迭代实现部分了.注意调用的结果是通过形参传递就可以了.而Acc就是辅助变量,所以调用应该通过Acc传递.
- | Tail_Recursion_Forest([H|T],Acc) ->
- | Tail_Recursion_Forest(T,[H|Acc]).
所以尾递归实现的完整代码如下:
- | %% @Func Reverse_Forest
- | %% @Breif 倒转List中的Element(尾递归实现)
- | Tail_Recursion_Forest(List) ->
- | Tail_Recursion_Forest(List,[]).
- | Tail_Recursion_Forest([],Acc) -> Acc;
- | Tail_Recursion_Forest([H|T],Acc) ->
- | Tail_Recursion_Forest(T,[H|Acc]).
Example Three:
- | %% @Func Sublist_Forest
- | %% @Breif 返回一个List中的前N个Elements
- | Sublist_Forest(_,0) -> [];
- | Sublist_Forest([],_) -> [];
- | Sublist_Forest([H|T],N) when N > 0 ->
- | [H|Sublist_Forest(T,N-1)].
下面是尾递归实现的代码:
Tail Recursion实现:
- | %% @Func Tail_Sublist_Forest
- | %% @Breif 返回一个List中的前N个Elements(尾递归实现)
- | Tail_Sublist_Forest(List,N) -> Tail_Sublist_Forest(List,N,[]).
- | Tail_Sublist_Forest(_,0,SubList) -> SubList;
- | Tail_Sublist_Forest([],_,SubList) -> SubList;
- | Tail_Sublist_Forest([H|T],N,SubList) ->
- | Tail_Sublist_Forest(T,N-1,[H|SubList]).
Tips:
tail recursion as seen here is not making the memory grow because
when the virtual machine sees a function calling itself in a tail position
(the last expression to be evaluated in a function), it eliminates the current
stack frame. This is called tail-call optimisation (TCO) and it is a special case
of a more general optimisation named Last Call Optimisation (LCO).
LCO is done whenever the last expression to be evaluated in a function body
is another function call. When that happens, as with TCO, the Erlang VM avoids
storing the stack frame. As such tail recursion is also possible between multiple
functions. As an example, the chain of functions a() -> b(). b() -> c(). c() -> a().
will effectively create an infinite loop that won't go out of memory as LCO avoids
overflowing the stack. This principle, combined with our use of accumulators
is what makes tail recursion useful.
上面这段小贴士的主要是说明Tail Recursion为什么和普通的Recursion不同,不会造成Stack Flow.
同时也说明了EVM对Tail Recursion的优化.
Erlang , Recursion World !!!! ~~~~ ~,~
- erlang递归和尾递归
- erlang 尾递归
- Erlang尾递归
- Erlang 尾递归
- erlang的递归与尾递归
- Erlang学习:递归和尾递归
- erlang递归
- erlang杂记十二--再说尾递归
- erlang循环结构:尾递归,列表解析
- [Erlang 0050]用fun在Erlang Shell中编写尾递归
- [Erlang 0056] 用fun在Erlang Shell中编写尾递归 Ⅱ
- erlang的shell里写一个尾递归
- erlang 的快排递归
- Erlang函数递归调用模式
- Erlang递归的性能问题:写出正确的尾递归代码
- Erlang 学习笔记 (2) -- 列表, 尾递归(循环语言的代替)
- 浅谈Erlang中最常用的编程模式--尾递归调用
- erlang throw跳出递归的妙用
- OgreMax 导出
- java代码规范
- 开源流媒体服务器Red5实施案列分析
- 分享23款使用纯CSS3生成的知名logo设计
- Python 函数式编程文章合集
- erlang 尾递归
- 【Android】布局优化
- Android的Activity屏幕切换动画-左右滑动深入与实战
- 《计算机教育》专题报道:充满快乐的提高班
- 基于压缩传感的脉冲GPR成像技术研究(硕士学位论文初稿20111230)
- jQuery 导航菜单点击伸缩展开效果的JS特效
- Java 使用poi导入excel,结合xml文件进行数据验证的例子(增加了jar包)
- POJ1002
- 关于字符串驻留