浏览 471 次
|
精华帖 (0) :: 良好帖 (0) :: 新手帖 (4) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
时间:2008-02-24 关键字: erlang 尾递归 循环 只读 list
ErLang Map 函数的尾递归形式
循环语句需要计数器变量控制循环次数,而计数器变量需要多次改变数值。ErLang语言不支持可以重复赋值的变量,因而也不支持循环语句。 ErLang程序员只能用递归表示循环。有些服务程序需要运行在在一个无穷循环中。 while true listen and respond to user request …. 这种情况下,ErLang程序也要写成无穷递归的形式。在ErLang中,无穷递归必须写成尾递归(Tail Recursion)的形式。因为ErLang是栈语言,如果是非尾递归的递归形式,无穷递归必然引起运行栈的无限膨胀。 下面我们来看一个非尾递归形式转化为尾递归的例子。 ErLang不支持循环语句,而是采用Map、Reduce等便利函数把递归形式简化为类似循环的形式。 map函数的定义为,用一个函数处理一个List中的每一个元素,并且产生每一个结果元素,这些结果元素构成一个新的List,作为返回值。 map函数的调用形式为: map( %% 定义一个匿名函数,作为函数体。函数参数就是List中的每一个元素 fun(Item) -> do something with Item return a Result Item of processing the Item end, List %% 第二个参数List。表示要处理的源List。 ) map函数的具体例子就不多说了。这是比较常见的函数调用。 我们来看map函数的实现。 map(Visit, [] ) -> [] ; map(Visit, [H | T]) -> [Vsit(H) | map(Visit, T)]. 我们看到,上述实现方法里面的递归调用,不是尾递归。 因此运行的过程中,运行栈不断地增长,长到头之后,运行栈再递减。 下面我们把map函数改写成尾递归形式。 由于ErLang的变量都是final的,不能重复赋值。因此我们只能够给List添加一个头,而不能添加尾。所以,我们要在最后把处理结果倒置一下。 map(Visit, L) -> R = process( Visit, L, [] ), lists:reverse( R ). process( Visit, [], R ) -> R; process( Visit, [H | T], R) -> RH = Visit( H ), process(Visit, T, [RH | R]). 我们看到,实际上,我们相当于用一个存放结果的R List代替了运行栈。每一次处理元素的结果都会放入到R这个List当中。 上述代码是尾递归形式,在运行过程,运行栈保持不变。当然,R这个结果List却在不断地增长。相当于自己用一个List代替了运行栈。只不过自己维护的这个List是在堆里面分配的,不受到运行栈大小的限制,只受到内存的限制。 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
时间:2008-02-25
Erlang中所有的进程处理函数都应该是尾递归的。
|
|
| 返回顶楼 | |






