<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>def Tenako.blog () end &#187; tco</title>
	<atom:link href="http://blog.tenako.com/tag/tco/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.tenako.com</link>
	<description></description>
	<lastBuildDate>Thu, 12 Aug 2010 19:26:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Ruby: TCO (Tail Call Optimization)</title>
		<link>http://blog.tenako.com/2009/06/01/ruby-tco-tail-call-optimization/</link>
		<comments>http://blog.tenako.com/2009/06/01/ruby-tco-tail-call-optimization/#comments</comments>
		<pubDate>Mon, 01 Jun 2009 22:21:13 +0000</pubDate>
		<dc:creator>farruco</dc:creator>
				<category><![CDATA[programacion]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[recursividad]]></category>
		<category><![CDATA[tco]]></category>

		<guid isPermaLink="false">http://blog.tenako.com/?p=130</guid>
		<description><![CDATA[Leyendo el libro de Programming Erlang descubrí un concepto que no conocia: funciones tail-recursive. En esta pagina lo explican bastante bien (entre otros tipos de recursividad), pero basicamente una función tail-recursive es aquella que no tiene ninguna operación pendiente de ejecutar tras la llamada recursiva. En estas funciones, la llamada recursiva puede ser substituida simplemente [...]]]></description>
			<content:encoded><![CDATA[<p>Leyendo el libro de <a href="http://www.pragprog.com/titles/jaerlang/programming-erlang" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.pragprog.com');" target="_blank">Programming Erlang</a> descubrí un concepto que no conocia: funciones <em>tail-recursive</em>.</p>
<p>En <a href="http://triton.towson.edu/~akayabas/COSC455_Spring2000/Recursion_Iteration.htm" onclick="javascript:pageTracker._trackPageview('/outbound/article/triton.towson.edu');" target="_blank">esta pagina</a> lo explican bastante bien (entre otros tipos de recursividad), pero basicamente una función <em>tail-recursive</em> es aquella que no tiene ninguna operación pendiente de ejecutar tras la llamada recursiva. En estas funciones, la llamada recursiva puede ser substituida simplemente por un salto al comienzo de la función que se llama, con lo que se ahorra espacio en el <em>stack</em>. De esto ultimo se encarga el compilador y es lo que se conoce como <a href="http://c2.com/cgi/wiki?TailCallOptimization" onclick="javascript:pageTracker._trackPageview('/outbound/article/c2.com');" target="_blank">Tail Call Optimization</a> (TCO a partir de ahora).</p>
<p>Así que aparentemente la TCO mola, ¿No?</p>
<p>El problema es que <a href="http://www.ruby-lang.org/es/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.ruby-lang.org');" targe="_blank">Ruby</a> no tiene implementada  TCO en su maquina virtual con lo que independientemente de como estructuremos nuestras funciones recursivas, siempre estaremos limitados por el tamaño de nuestra Stack.</p>
<p>Pero siempre hay solución para todo y con Ruby, más. En <a href="http://judofyr.net/posts/tailin-ruby.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/judofyr.net');" target="_blank">ésta página</a> dan dos soluciones para tener una pseudo-TCO.</p>
<p>Copio y pego la primera solución:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> <span style="color:#9966CC; font-weight:bold;">Class</span>
  <span style="color:#008000; font-style:italic;"># Sweet stuff!</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> tailcall_optimize<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006600; font-weight:bold;">*</span>methods <span style="color:#006600; font-weight:bold;">&#41;</span>
    methods.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |meth|
      org = instance_method<span style="color:#006600; font-weight:bold;">&#40;</span> meth <span style="color:#006600; font-weight:bold;">&#41;</span>
      define_method<span style="color:#006600; font-weight:bold;">&#40;</span> meth <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> |*args|
        <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#CC00FF; font-weight:bold;">Thread</span>.<span style="color:#9900CC;">current</span><span style="color:#006600; font-weight:bold;">&#91;</span> meth <span style="color:#006600; font-weight:bold;">&#93;</span>
          throw<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:recurse</span>, args <span style="color:#006600; font-weight:bold;">&#41;</span>
        <span style="color:#9966CC; font-weight:bold;">else</span>
          <span style="color:#CC00FF; font-weight:bold;">Thread</span>.<span style="color:#9900CC;">current</span><span style="color:#006600; font-weight:bold;">&#91;</span> meth <span style="color:#006600; font-weight:bold;">&#93;</span> = org.<span style="color:#9900CC;">bind</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#0000FF; font-weight:bold;">self</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
          result = <span style="color:#CC0066; font-weight:bold;">catch</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:done</span> <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
            <span style="color:#CC0066; font-weight:bold;">loop</span> <span style="color:#9966CC; font-weight:bold;">do</span>
              args = <span style="color:#CC0066; font-weight:bold;">catch</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:recurse</span> <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
                throw<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:done</span>, <span style="color:#CC00FF; font-weight:bold;">Thread</span>.<span style="color:#9900CC;">current</span><span style="color:#006600; font-weight:bold;">&#91;</span> meth <span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">call</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006600; font-weight:bold;">*</span>args <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
              <span style="color:#9966CC; font-weight:bold;">end</span>
            <span style="color:#9966CC; font-weight:bold;">end</span>
          <span style="color:#9966CC; font-weight:bold;">end</span>
          <span style="color:#CC00FF; font-weight:bold;">Thread</span>.<span style="color:#9900CC;">current</span><span style="color:#006600; font-weight:bold;">&#91;</span> meth <span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#0000FF; font-weight:bold;">nil</span>
          result
        <span style="color:#9966CC; font-weight:bold;">end</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> TCOTest
  <span style="color:#008000; font-style:italic;"># tail-recursive factorial</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> fact<span style="color:#006600; font-weight:bold;">&#40;</span> n, acc = <span style="color:#006666;">1</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">if</span> n <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006666;">2</span> <span style="color:#9966CC; font-weight:bold;">then</span> acc <span style="color:#9966CC; font-weight:bold;">else</span> fact<span style="color:#006600; font-weight:bold;">&#40;</span> n<span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">1</span>, n<span style="color:#006600; font-weight:bold;">*</span>acc <span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># length of factorial</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> fact_size<span style="color:#006600; font-weight:bold;">&#40;</span> n <span style="color:#006600; font-weight:bold;">&#41;</span>
    fact<span style="color:#006600; font-weight:bold;">&#40;</span> n <span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">size</span>
  <span style="color:#9966CC; font-weight:bold;">rescue</span>
    $!
  <span style="color:#9966CC; font-weight:bold;">end</span>   
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
t = TCOTest.<span style="color:#9900CC;">new</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># normal method</span>
<span style="color:#CC0066; font-weight:bold;">puts</span> t.<span style="color:#9900CC;">fact_size</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">10000</span> <span style="color:#006600; font-weight:bold;">&#41;</span>  <span style="color:#008000; font-style:italic;"># =&gt; stack level too deep</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># enable tail-call optimization</span>
<span style="color:#9966CC; font-weight:bold;">class</span> TCOTest
  tailcall_optimize <span style="color:#ff3333; font-weight:bold;">:fact</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># tail-call optimized method</span>
<span style="color:#CC0066; font-weight:bold;">puts</span> t.<span style="color:#9900CC;">fact_size</span><span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">10000</span> <span style="color:#006600; font-weight:bold;">&#41;</span>  <span style="color:#008000; font-style:italic;"># =&gt; 14808</span></pre></div></div>

<p>Esta solución consiste en jugar con catch&#8217;s,throw&#8217;s y Thread.current para relanzar el mismo método una y otra vez sin tener que crear un nuevo frame en el Stack, ya que el codigo del metodo se encuentra definido en un bloque y por tanto reutiliza el codigo. </p>
<p>La segunda opción:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">def</span> fib<span style="color:#006600; font-weight:bold;">&#40;</span>i, n = <span style="color:#006666;">1</span>, result = 0<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">if</span> i == <span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">1</span>
    result
  <span style="color:#9966CC; font-weight:bold;">else</span>
    i, n, result = i <span style="color:#006600; font-weight:bold;">-</span> <span style="color:#006666;">1</span>, n <span style="color:#006600; font-weight:bold;">+</span> result, n
    <span style="color:#9966CC; font-weight:bold;">redo</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
fib<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">10000</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>

<p>Esta solución consiste en hacer uso de la palabra <a href="http://www.rubyist.net/~slagell/ruby/control.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.rubyist.net');" target="_blank">redo</a> la cual reinicia la ejecución de cualquier loop o iterador. El problema con redo es que, como acabo de decir, solo se puede utilizar en loops o iteradores y el método fib anterior no es ninguno de ellos. Por lo que el autor de la página de que se extrajeron las soluciones dice:</p>
<blockquote><p>Unfortunately, “The redo statement restarts the current iteration of a loop or iterator”, so it only throws a LocalJumpError</p></blockquote>
<p><img src="http://blog.tenako.com/wp-content/uploads/2009/06/ruby_spartan1.png" alt="ruby_spartan1" title="ruby_spartan1" width="550" height="343" class="aligncenter size-full wp-image-153" /></p>
<p>Gracias señor espartano. </p>
<p>Así es, esto es Ruby y siempre hay un workaround para todo. En este caso, consiste en crear un nuevo método cuyo cuerpo este contenido en un bloque.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby ruby" style="font-family:monospace;">define_method<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:acc</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i, n, result|
  <span style="color:#9966CC; font-weight:bold;">if</span> i == <span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">1</span>
    result
  <span style="color:#9966CC; font-weight:bold;">else</span>
    i, n, result = i <span style="color:#006600; font-weight:bold;">-</span> <span style="color:#006666;">1</span>, n <span style="color:#006600; font-weight:bold;">+</span> result, n
    <span style="color:#9966CC; font-weight:bold;">redo</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">def</span> fib<span style="color:#006600; font-weight:bold;">&#40;</span>i<span style="color:#006600; font-weight:bold;">&#41;</span>
  acc<span style="color:#006600; font-weight:bold;">&#40;</span>i, <span style="color:#006666;">1</span>, 0<span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
fib<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">10000</span><span style="color:#006600; font-weight:bold;">&#41;</span>  <span style="color:#008000; font-style:italic;"># Yeah!</span></pre></div></div>

<p>Y ya podemos utilizar redo. Fin!!</p>
<p>Para mas información, hay un thread en esta lista de correo en el que debaten sobre este tema: <a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/171075" onclick="javascript:pageTracker._trackPageview('/outbound/article/blade.nagaokaut.ac.jp');" target="_blank">Ruby tail recursion</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tenako.com/2009/06/01/ruby-tco-tail-call-optimization/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
