<div class="gmail_quote">On Fri, Apr 23, 2010 at 17:29, Matthew Flatt <span dir="ltr">&lt;<a href="mailto:mflatt@cs.utah.edu">mflatt@cs.utah.edu</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div class="im">At Thu, 22 Apr 2010 20:28:55 -0400, &quot;Skeptic .&quot; wrote:<br>
&gt; I&#39;m curious to know how in PLT what kind of performance difference<br>
&gt; (in the broad sense) would be found when comparing a tree-recursive<br>
&gt; procedure to a tail-recursive one that use an explicit stack and a<br>
&gt; non-trivial nested list, e.g. flatten, count-atoms and the like.<br>
<br>
</div>It&#39;s generally better to write in direct, tree-recursive style.<br>
<br>
For example, many systems implement `map&#39; in a tail-recursive way to<br>
avoid deep recursion:<br>
<br>
 (define (map1/loop f l)<br>
   (let loop ([l l][accum null])<br>
     (if (null? l)<br>
         (reverse accum)<br>
         (loop (cdr l) (cons (f (car l)) accum)))))<br>
<br>
The single-list `map&#39; in PLT Scheme, however, is implemented in direct<br>
style:<br>
<br>
 (define (map1 f l)<br>
   (if (null? l)<br>
       null<br>
       (cons (f (car l)) (map1 f (cdr l)))))<br>
<br>
The direct style usually performs better in PLT Scheme, and we don&#39;t<br>
have to worry about a special limit on continuation sizes (i.e., no<br>
stack overflow).<br>
<br>
The direct style performs better in the `map&#39; case because the GC can<br>
process continuation frames more efficiently than `cons&#39; chains. That<br>
isn&#39;t typical across implementations; the GC in many Scheme systems is<br>
especially highly tuned for pairs, and less so for continuation frames.<br>
<br>
<br>
Of course, if you want to just count the elements of a list, then a<br>
loop version<br>
<br>
  (define (count/tail l)<br>
    (let loop ([l l][accum 0])<br>
      (if (null? l)<br>
          accum<br>
          (loop (cdr l) (add1 accum)))))<br>
<br>
is 10 times faster than a direct version<br>
<br>
  (define (count l)<br>
    (if (null? l)<br>
        0<br>
        (+ 1 (count (cdr l)))))<br>
<br>
The difference is that the number result can be accumulated<br>
left-to-right and doesn&#39;t have to be &quot;reversed&quot; at the end. For<br>
performance, not having a continuation at all is better than having<br>
one.<br>
<br>
<br>
Those examples were not tree recursion, but they point to a general<br>
answer: If your computation has a continuation, let the runtime system<br>
represent it. Your program will be easier to write and read in direct<br>
style, and it will probably perform as well (if not better) as with an<br>
explicit representation.<br>
<div><div></div><br></div></blockquote></div><br>While programming a cellular automaton, I first used `foldl&#39; to do some 
computation on the list of neighbors.<br>
That was awfully slow, so I tried with a hand-written loop, and it 
became much faster -- fast enough for fluid visual effect.<br>
I&#39;m not sure exactly why `foldl&#39; was so slow though...<br><br>