<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>
<channel>
	<title>Comments on: 写出正确的尾递归代码</title>
	<atom:link href="http://erlang-china.org/study/the-right-tail-recursive.html/feed" rel="self" type="application/rss+xml" />
	<link>http://erlang-china.org/study/the-right-tail-recursive.html</link>
	<description>erlang 中文社区</description>
	<pubDate>Mon, 01 Dec 2008 19:58:33 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.5</generator>
		<item>
		<title>By: Daze</title>
		<link>http://erlang-china.org/study/the-right-tail-recursive.html#comment-3322</link>
		<dc:creator>Daze</dc:creator>
		<pubDate>Thu, 27 Dec 2007 07:52:41 +0000</pubDate>
		<guid isPermaLink="false">http://erlang-china.org/misc/the-right-tail-recursive.html#comment-3322</guid>
		<description>呵呵，咬文嚼字一下，既然在堆栈上那就不是传统意义上的“变量”了，在这里用“变量”这个词，也许会让人感到迷惑。</description>
		<content:encoded><![CDATA[<p>呵呵，咬文嚼字一下，既然在堆栈上那就不是传统意义上的“变量”了，在这里用“变量”这个词，也许会让人感到迷惑。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: kgha</title>
		<link>http://erlang-china.org/study/the-right-tail-recursive.html#comment-3291</link>
		<dc:creator>kgha</dc:creator>
		<pubDate>Sat, 15 Dec 2007 17:59:52 +0000</pubDate>
		<guid isPermaLink="false">http://erlang-china.org/misc/the-right-tail-recursive.html#comment-3291</guid>
		<description>楼上说的很对，尾递归是基于堆栈不额外增加的前提，不额外增加堆栈并不表示不能改变堆栈上数据的值，尾递归一般需要在堆栈上额外增加一个用于记录操作函数返回结果的变量，然后对这个变量和每次递归函数的返回结果迭代运算，最后将此变量作为最终结果返回</description>
		<content:encoded><![CDATA[<p>楼上说的很对，尾递归是基于堆栈不额外增加的前提，不额外增加堆栈并不表示不能改变堆栈上数据的值，尾递归一般需要在堆栈上额外增加一个用于记录操作函数返回结果的变量，然后对这个变量和每次递归函数的返回结果迭代运算，最后将此变量作为最终结果返回</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Daze</title>
		<link>http://erlang-china.org/study/the-right-tail-recursive.html#comment-186</link>
		<dc:creator>Daze</dc:creator>
		<pubDate>Sun, 29 Jul 2007 16:10:03 +0000</pubDate>
		<guid isPermaLink="false">http://erlang-china.org/misc/the-right-tail-recursive.html#comment-186</guid>
		<description>其实递归和尾递归并不是很复杂的概念，很多人觉得不好理解在我看来也许是眼睛抬得有点高了，只看到高级的数学概念，当然不是说这样不好，玩 FP 嘛自然就是在玩数学，只是有时向另外的方向看一看，也许会有想不到的收获，现在不妨让我们从低级的东东入手，来看一看递归和尾递归。

下面我们用 forth 来写几个不同版本的阶乘函数，forth 不是函数型语言，也不完全是通常所说的命令式语言，而是一个很低级（也许比 c 还低级）、很接近汇编的“古怪”语言，但写出来的代码却惊人的短小，执行效率也非常高，但既不能说它是编译型也不能说是解释型，总之是个很有趣的东东，我发现在学习别的语言（像 FP ）遇到困难时，对照 forth 的概念，难题往往迎刃而解，不胡扯了，回到正题:

&lt;coolcode&gt;
: 递归阶乘 ( n -- n! )  dup 1 &lt;if drop 1
    else dup 1- 递归阶乘 *
    then ;
&lt;/coolcode&gt;

或者

&lt;coolcode&gt;
: 弟二个递归阶乘 ( n -- n! )  dup 1- 0; 弟二个递归阶乘 * ;
&lt;/coolcode&gt;

这两个 word （也就是函数）是一样的，但第一个容易理解，而第二个非常之小，编译后只有 22 bytes ，请注意括号中的是注释，说明堆栈在 word 执行前后的变化情况，现在调用它来计算 5 和 6 的阶乘:

&lt;coolcode&gt;
ok&gt;5 递归阶乘 .
120
ok&gt;6 弟二个递归阶乘 .
720
&lt;/coolcode&gt;

细节就不在这说了，总之你执行这个的时候，随着递归次数的增加，你的堆栈会最终变成 （ 5 4 3 2 1 1 ），然后顺序做乘法，最后得到结果 120 ，看到了吧，堆栈会随着递归的次数不断的增长，如果你用它来计算一个很大的数，结果必然是堆栈溢出， GAME OVER 了，下面来看尾递归:

&lt;coolcode&gt;
&#124; 尾递归(Tail-recursive)，不会增加栈空间
: 尾递归阶乘 ( 1 n -- n! ) dup 2 &lt;if drop ;then dup 1- dup 1- &gt;r * * r&gt; 尾递归阶乘 ;
&lt;/coolcode&gt;

代码写得有点难看，“dup 1-” 连着用了两次，不管了，大家将就着看吧！如果有高手看到这难看的 code ，还请多多包涵、多多指点，下面调用它来计算 5 的阶乘:

&lt;coolcode&gt;
ok&gt;1 5 尾递归阶乘 .
120
&lt;/coolcode&gt;

程序运行之前堆栈是（ 1 5 ），执行了一次后变成了（ 20 3 ），这是什么啊？呵呵，5 × 4 × 1 ＝ 20 ，这个结果放到了原来 1 的位置上，下一个要计算的数 3 放到了原来 5 的位置上，也就是栈顶，接着再一次递归调用，3 × 2 × 20 ＝ 120 ，下一个要计算的数是 1 ，堆栈变成了（ 120 1 ），最后，由于 1 &lt; 2 ，执行 drop 丢掉 1 ，然后停止递归，堆栈中留下了结果 120 。

现在明白了吧，所谓尾递归，就是说递归函数要在每次程序的最后调用自己，同时每次递归都要与上一次的运算结果共同作用产生一个新结果（第一次要多输入一个用于保存中间结果的参数，在这个例子中就是 1 。），然后把这个结果放回堆栈中，并等待下一次的调用，这样的话，堆栈并没有增长也就不存在溢出的问题了。而通常的递归是每次递归产生的结果是不完全并独立的，并不立即与上一次的结果进行运算，而是一个个的保存在堆栈中，导致堆栈不断的增长，到最后递归结束时，再来做所有剩下的运算。楼上所说的“是不是尾递归一个简单的判断方法就是看它的函数返回涉及不涉及额外运算”，我觉得并不完全，尾递归可以涉及额外的运算，只要你保证下次递归开始时，堆栈还是原来的样子就行了。

好了，但还有一个问题，就是现在每次调用尾递归程序时，要多输入一个参数 1 ，是有点难看啊！呵呵，这个好办，象上面的 Erlang 版累加函数一样，封装一下 word “尾递归阶乘”吧:

&lt;coolcode&gt;
: factorial ( n -- n! ) 1 swap 尾递归阶乘 ;
&lt;/coolcode&gt;

测试一下:
&lt;coolcode&gt;
ok&gt;10 factorial .
3628800
&lt;/coolcode&gt;

如果你看懂了上面的 forth 代码，相信你一定会觉得不过如此，并且可以结合前面的 Erlang 代码来看，也就明白了 Erlang 的尾递归到底在做什么！

为方便参考，这里也给出一个循环的版本:

&lt;coolcode&gt;
: 循环阶乘 ( n -- n! ) 1 tuck max 1+ 1 do i * loop ;
&lt;/coolcode&gt;

运行:
&lt;coolcode&gt;
ok&gt;8 循环阶乘 .
40320
&lt;/coolcode&gt;

注意，这里堆栈也并没有增长，但却使用了一个循环变量: i 。</description>
		<content:encoded><![CDATA[<p>其实递归和尾递归并不是很复杂的概念，很多人觉得不好理解在我看来也许是眼睛抬得有点高了，只看到高级的数学概念，当然不是说这样不好，玩 FP 嘛自然就是在玩数学，只是有时向另外的方向看一看，也许会有想不到的收获，现在不妨让我们从低级的东东入手，来看一看递归和尾递归。</p>
<p>下面我们用 forth 来写几个不同版本的阶乘函数，forth 不是函数型语言，也不完全是通常所说的命令式语言，而是一个很低级（也许比 c 还低级）、很接近汇编的“古怪”语言，但写出来的代码却惊人的短小，执行效率也非常高，但既不能说它是编译型也不能说是解释型，总之是个很有趣的东东，我发现在学习别的语言（像 FP ）遇到困难时，对照 forth 的概念，难题往往迎刃而解，不胡扯了，回到正题:</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">: 递归阶乘 ( n -- n! )&nbsp; dup 1 &lt;if drop 1</li>
<li>&nbsp;&nbsp; &nbsp;else dup 1- 递归阶乘 *</li>
<li>&nbsp;&nbsp; &nbsp;then ;</li></ol></div>
<p>或者</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">: 弟二个递归阶乘 ( n -- n! )&nbsp; dup 1- 0; 弟二个递归阶乘 * ;</li></ol></div>
<p>这两个 word （也就是函数）是一样的，但第一个容易理解，而第二个非常之小，编译后只有 22 bytes ，请注意括号中的是注释，说明堆栈在 word 执行前后的变化情况，现在调用它来计算 5 和 6 的阶乘:</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">ok&gt;5 递归阶乘 .</li>
<li>120</li>
<li>ok&gt;6 弟二个递归阶乘 .</li>
<li>720</li></ol></div>
<p>细节就不在这说了，总之你执行这个的时候，随着递归次数的增加，你的堆栈会最终变成 （ 5 4 3 2 1 1 ），然后顺序做乘法，最后得到结果 120 ，看到了吧，堆栈会随着递归的次数不断的增长，如果你用它来计算一个很大的数，结果必然是堆栈溢出， GAME OVER 了，下面来看尾递归:</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">| 尾递归(Tail-recursive)，不会增加栈空间</li>
<li>: 尾递归阶乘 ( 1 n -- n! ) dup 2 &lt;if drop ;then dup 1- dup 1- &gt;r * * r&gt; 尾递归阶乘 ;</li></ol></div>
<p>代码写得有点难看，“dup 1-” 连着用了两次，不管了，大家将就着看吧！如果有高手看到这难看的 code ，还请多多包涵、多多指点，下面调用它来计算 5 的阶乘:</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">ok&gt;1 5 尾递归阶乘 .</li>
<li>120</li></ol></div>
<p>程序运行之前堆栈是（ 1 5 ），执行了一次后变成了（ 20 3 ），这是什么啊？呵呵，5 × 4 × 1 ＝ 20 ，这个结果放到了原来 1 的位置上，下一个要计算的数 3 放到了原来 5 的位置上，也就是栈顶，接着再一次递归调用，3 × 2 × 20 ＝ 120 ，下一个要计算的数是 1 ，堆栈变成了（ 120 1 ），最后，由于 1 < 2 ，执行 drop 丢掉 1 ，然后停止递归，堆栈中留下了结果 120 。</p>
<p>现在明白了吧，所谓尾递归，就是说递归函数要在每次程序的最后调用自己，同时每次递归都要与上一次的运算结果共同作用产生一个新结果（第一次要多输入一个用于保存中间结果的参数，在这个例子中就是 1 。），然后把这个结果放回堆栈中，并等待下一次的调用，这样的话，堆栈并没有增长也就不存在溢出的问题了。而通常的递归是每次递归产生的结果是不完全并独立的，并不立即与上一次的结果进行运算，而是一个个的保存在堆栈中，导致堆栈不断的增长，到最后递归结束时，再来做所有剩下的运算。楼上所说的“是不是尾递归一个简单的判断方法就是看它的函数返回涉及不涉及额外运算”，我觉得并不完全，尾递归可以涉及额外的运算，只要你保证下次递归开始时，堆栈还是原来的样子就行了。</p>
<p>好了，但还有一个问题，就是现在每次调用尾递归程序时，要多输入一个参数 1 ，是有点难看啊！呵呵，这个好办，象上面的 Erlang 版累加函数一样，封装一下 word “尾递归阶乘”吧:</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">: factorial ( n -- n! ) 1 swap 尾递归阶乘 ;</li></ol></div>
<p>测试一下:</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">ok&gt;10 factorial .</li>
<li>3628800</li></ol></div>
<p>如果你看懂了上面的 forth 代码，相信你一定会觉得不过如此，并且可以结合前面的 Erlang 代码来看，也就明白了 Erlang 的尾递归到底在做什么！</p>
<p>为方便参考，这里也给出一个循环的版本:</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">: 循环阶乘 ( n -- n! ) 1 tuck max 1+ 1 do i * loop ;</li></ol></div>
<p>运行:</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">ok&gt;8 循环阶乘 .</li>
<li>40320</li></ol></div>
<p>注意，这里堆栈也并没有增长，但却使用了一个循环变量: i 。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: piggybox</title>
		<link>http://erlang-china.org/study/the-right-tail-recursive.html#comment-129</link>
		<dc:creator>piggybox</dc:creator>
		<pubDate>Wed, 11 Jul 2007 18:55:37 +0000</pubDate>
		<guid isPermaLink="false">http://erlang-china.org/misc/the-right-tail-recursive.html#comment-129</guid>
		<description>是不是尾递归一个简单的判断方法就是看它的函数返回涉及不涉及额外运算，涉及的就不是尾递归，因为需要保留状态到stack里面。

递归一般用在不确定循环次数的场合，确定的就用list comprehension，比for好啊。不确定次数的循环传统上用while true里面再跳转也让人糊涂，对吧？</description>
		<content:encoded><![CDATA[<p>是不是尾递归一个简单的判断方法就是看它的函数返回涉及不涉及额外运算，涉及的就不是尾递归，因为需要保留状态到stack里面。</p>
<p>递归一般用在不确定循环次数的场合，确定的就用list comprehension，比for好啊。不确定次数的循环传统上用while true里面再跳转也让人糊涂，对吧？</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: jackyz</title>
		<link>http://erlang-china.org/study/the-right-tail-recursive.html#comment-65</link>
		<dc:creator>jackyz</dc:creator>
		<pubDate>Tue, 08 May 2007 01:48:15 +0000</pubDate>
		<guid isPermaLink="false">http://erlang-china.org/misc/the-right-tail-recursive.html#comment-65</guid>
		<description>@simohayha scheme 俺不懂的说。

说实话，我觉得尾递归在语法表达上让人糊涂，不好理解，完全不如 for/while 之类的语法来得简单明了。

窃以为 erlang 强调尾递归实属无奈，因为在语法层面（变量绑定一次不可更改）它并没有实现循环其他简便易行的方式。一个语言如果连循环都写得费劲，又有何用？好在尾递归解此厄困，善哉善哉。就是比较难懂一点。 :D</description>
		<content:encoded><![CDATA[<p>@simohayha scheme 俺不懂的说。</p>
<p>说实话，我觉得尾递归在语法表达上让人糊涂，不好理解，完全不如 for/while 之类的语法来得简单明了。</p>
<p>窃以为 erlang 强调尾递归实属无奈，因为在语法层面（变量绑定一次不可更改）它并没有实现循环其他简便易行的方式。一个语言如果连循环都写得费劲，又有何用？好在尾递归解此厄困，善哉善哉。就是比较难懂一点。 <img src='http://erlang-china.org/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: simohayha</title>
		<link>http://erlang-china.org/study/the-right-tail-recursive.html#comment-63</link>
		<dc:creator>simohayha</dc:creator>
		<pubDate>Sun, 06 May 2007 11:08:03 +0000</pubDate>
		<guid isPermaLink="false">http://erlang-china.org/misc/the-right-tail-recursive.html#comment-63</guid>
		<description>其实你所说的那些erlang的特性，也就是 函数式语言的特性了，我用scheme也写了个尾递归，这个就非常清晰了，尾递归也就是多引入了几个参数。

[code]
(define (f a b n)
  (if (= n 1)
      a
      (f (+ a b) (+ b 1) (- n 1))))
(define (g n)
  (f 1 2 n))
(g 3)
[/code]</description>
		<content:encoded><![CDATA[<p>其实你所说的那些erlang的特性，也就是 函数式语言的特性了，我用scheme也写了个尾递归，这个就非常清晰了，尾递归也就是多引入了几个参数。</p>
<p>[code]<br />
(define (f a b n)<br />
  (if (= n 1)<br />
      a<br />
      (f (+ a b) (+ b 1) (- n 1))))<br />
(define (g n)<br />
  (f 1 2 n))<br />
(g 3)<br />
[/code]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: jackyz</title>
		<link>http://erlang-china.org/study/the-right-tail-recursive.html#comment-62</link>
		<dc:creator>jackyz</dc:creator>
		<pubDate>Sun, 06 May 2007 08:55:36 +0000</pubDate>
		<guid isPermaLink="false">http://erlang-china.org/misc/the-right-tail-recursive.html#comment-62</guid>
		<description>@simohayha，你说的有道理，关于为什么需要在 erlang 中用尾递归来实现循环，我是这么理解的。

其他语言之中的循环，如 for/while 的都依赖于一个共享的变量，通过更改和检查这个共享变量的值，实现循环的流程控制。而 erlang 的一个原则是 share nothing，变量只能一次 bind ，而且设置之后不能改变。在这个前提下，上述循环的实现方式就不再可行。

函数的参数和运算结果，属于中间值，他的使用并不违背这一原则，实际上，函数的递归也是一种循环，只不过，如果不优化递归对于资源的占用，就没有实际应用的价值。

如果能解决资源消耗问题，那么递归对于 erlang 这样 share nothing 的语言，就是一个实现循环的绝好方法。所幸，要满足这样的优化条件，并不复杂，只需要保证函数本身的“可迭代性”就成。这一般可以通过增加表示迭代结果的参数来完成。比如：

&lt;coolcode lang="erlang"&gt;
fac(1) -&gt;
  1;
fac(N) -&gt;
  N + fac(N - 1).
&lt;/coolcode&gt;
优化后变成：
&lt;coolcode lang="erlang"&gt;
% 供外部调用的方法
fac(N) -&gt;
  % 内部调用尾递归的实现，X=1是初始值
  fac_i(N, 1).

% 尾递归的终结器
fac_i(1, X) -&gt;
  X;
% 尾递归的循环器
fac_i(N, X) -&gt;
  fac_i(N - 1, N + X).
&lt;/coolcode&gt;

可以留意到，函数的对外接口并没有改变，仍然是 fac/1 。但在它的实现函数上。主要的改变是：引入了一个 X 参数，这里 X 的值是上一次迭代的运算结果，而 N 已经变成了循环的控制变量(每次迭代 N 减1)，而 fac_i(1, X) 仍是这个尾递归的终结器。

增加一个参数，就把递归变成尾递归。其实还是挺简单的。</description>
		<content:encoded><![CDATA[<p>@simohayha，你说的有道理，关于为什么需要在 erlang 中用尾递归来实现循环，我是这么理解的。</p>
<p>其他语言之中的循环，如 for/while 的都依赖于一个共享的变量，通过更改和检查这个共享变量的值，实现循环的流程控制。而 erlang 的一个原则是 share nothing，变量只能一次 bind ，而且设置之后不能改变。在这个前提下，上述循环的实现方式就不再可行。</p>
<p>函数的参数和运算结果，属于中间值，他的使用并不违背这一原则，实际上，函数的递归也是一种循环，只不过，如果不优化递归对于资源的占用，就没有实际应用的价值。</p>
<p>如果能解决资源消耗问题，那么递归对于 erlang 这样 share nothing 的语言，就是一个实现循环的绝好方法。所幸，要满足这样的优化条件，并不复杂，只需要保证函数本身的“可迭代性”就成。这一般可以通过增加表示迭代结果的参数来完成。比如：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">fac</span><span style="color: Olive;">(</span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; </span><span style="color: Maroon;">1</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">fac</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; </span><span style="color: Blue;">N</span><span style="color: Gray;"> + </span><span style="color: Blue;">fac</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Gray;"> - </span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li></ol></div>
<p>优化后变成：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">% 供外部调用的方法</span></li>
<li><span style="color: Blue;">fac</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; </span><span style="color: #ffa500;">% 内部调用尾递归的实现，X=1是初始值</span></li>
<li><span style="color: Gray;">&nbsp; </span><span style="color: Blue;">fac_i</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: #ffa500;">% 尾递归的终结器</span></li>
<li><span style="color: Blue;">fac_i</span><span style="color: Olive;">(</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; </span><span style="color: Blue;">X</span><span style="color: Gray;">;</span></li>
<li><span style="color: #ffa500;">% 尾递归的循环器</span></li>
<li><span style="color: Blue;">fac_i</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">X</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; </span><span style="color: Blue;">fac_i</span><span style="color: Olive;">(</span><span style="color: Blue;">N</span><span style="color: Gray;"> - </span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;"> + </span><span style="color: Blue;">X</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li></ol></div>
<p>可以留意到，函数的对外接口并没有改变，仍然是 fac/1 。但在它的实现函数上。主要的改变是：引入了一个 X 参数，这里 X 的值是上一次迭代的运算结果，而 N 已经变成了循环的控制变量(每次迭代 N 减1)，而 fac_i(1, X) 仍是这个尾递归的终结器。</p>
<p>增加一个参数，就把递归变成尾递归。其实还是挺简单的。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: simohayha</title>
		<link>http://erlang-china.org/study/the-right-tail-recursive.html#comment-61</link>
		<dc:creator>simohayha</dc:creator>
		<pubDate>Sun, 06 May 2007 05:32:43 +0000</pubDate>
		<guid isPermaLink="false">http://erlang-china.org/misc/the-right-tail-recursive.html#comment-61</guid>
		<description>其实尾递归也就是一个线性迭代过程，递归计算过程和递归过程是不一样的，尾递归只是个递归过程，而不是一个递归计算过程，他的计算过程是迭代的，基本上非函数式的语言，他们对任何递归过程的解释所消耗的内存总与过程调用的数目成正比，即使计算过程是迭代的，所以这些语言就衍生出for,while 等等“循环结构”。</description>
		<content:encoded><![CDATA[<p>其实尾递归也就是一个线性迭代过程，递归计算过程和递归过程是不一样的，尾递归只是个递归过程，而不是一个递归计算过程，他的计算过程是迭代的，基本上非函数式的语言，他们对任何递归过程的解释所消耗的内存总与过程调用的数目成正比，即使计算过程是迭代的，所以这些语言就衍生出for,while 等等“循环结构”。</p>
]]></content:encoded>
	</item>
</channel>
</rss>
