<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE message PUBLIC
  "-//MLarc//DTD MLarc output files//EN"
  "../../mlarc.dtd"[
  <!ATTLIST message
    listname CDATA #REQUIRED
    title CDATA #REQUIRED
  >
]>

  <?xml-stylesheet href="../../mlarc.xsl" type="text/xsl"?>


<message 
  url="2003/01/66af9c604b2e1cbf5540394e5080e697"
  from="Andrew Kennedy &lt;akenn@m...&gt;"
  author="Andrew Kennedy"
  date="2003-01-24T15:35:08"
  subject="RE: [Caml-list] @, List.append, and tail recursion"
  prev="2003/01/886fb576d6d7551e0110c4b027508f41"
  next="2003/01/c580abbd3939d9ea05746164c0b9cf8e"
  next-in-thread="2003/01/624b5af3263b83ed919ac074b95954f7"
  prev-thread="2003/01/ca206608ecf5956dd3d853c07789a29d"
  next-thread="2003/01/5c86d82d713130bc02c3598ca34b3ae0"
  root="../../"
  period="month"
  listname="caml-list"
  title="Archives of the Caml mailing list">

<thread subject="RE: [Caml-list] @, List.append, and tail recursion">
<msg 
  url="2003/01/66af9c604b2e1cbf5540394e5080e697"
  from="Andrew Kennedy &lt;akenn@m...&gt;"
  author="Andrew Kennedy"
  date="2003-01-24T15:35:08"
  subject="RE: [Caml-list] @, List.append, and tail recursion">
<msg 
  url="2003/01/624b5af3263b83ed919ac074b95954f7"
  from="brogoff@s..."
  author="brogoff@s..."
  date="2003-01-30T01:44:30"
  subject="RE: [Caml-list] @, List.append, and tail recursion">
<msg 
  url="2003/01/592b98fe8dedf13711d78616753b71af"
  from="Christophe Raffalli &lt;Christophe.Raffalli@u...&gt;"
  author="Christophe Raffalli"
  date="2003-01-31T09:34:53"
  subject="Re: [Caml-list] @, List.append, and tail recursion">
<msg 
  url="2003/01/018ac7ba03a5d6d873c847f8d803a969"
  from="Brian Hurt &lt;brian.hurt@q...&gt;"
  author="Brian Hurt"
  date="2003-01-30T15:54:23"
  subject="Re: [Caml-list] @, List.append, and tail recursion">
</msg>
<msg 
  url="2003/01/f37d898ed760057b2a30d07937bc9aae"
  from="Mattias Waldau &lt;mattias.waldau@a...&gt;"
  author="Mattias Waldau"
  date="2003-01-31T10:33:46"
  subject="RE: [Caml-list] @, List.append, and tail recursion">
</msg>
</msg>
</msg>
</msg>
</thread>

<contents>
Brian,

The optimization you describe is sometimes known as
"tail modulo cons", and is an example of "destination-passing
style". In other words, the place to put the result (in
this case, the address of the tail of a just-constructed 
cons cell) is passed on in a tail-recursive call.

See "A Functional Representation of Data Structures with a Hole"
by Minamide in POPL'98.

http://www.score.is.tsukuba.ac.jp/~minamide/index.html

Although Minimide formalizes the problem in the context of
a typed intermediate language, it's probably quite easy to 
spot special cases quite far down the compiler pipeline.
- Andrew.

&gt; -----Original Message-----
&gt; From: Brian Hurt [mailto:brian.hurt@qlogic.com] 
&gt; Sent: Friday, January 24, 2003 12:48 AM
&gt; To: Ocaml Mailing List
&gt; Subject: [Caml-list] @, List.append, and tail recursion
&gt; 
&gt; 
&gt; 
&gt; I hit a bug recently wiith @ and List.append.  Since they're 
&gt; recursive, 
&gt; not tail-recursive, on long enough lists Ocaml thinks you've gone 
&gt; infinitely recursive and aborts.  The code:
&gt; 
&gt; 
&gt; let longlist len =
&gt;     let rec longlist_int v c acc =
&gt;         if (c == 0) then acc else longlist_int (v + 1) (c - 
&gt; 1) (v :: acc)
&gt;     in
&gt;     longlist_int 0 len []
&gt; ;;
&gt; 
&gt; let x = longlist 65536 ;;
&gt; 
&gt; List.append x [] ;;
&gt; 
&gt; Exits with:
&gt; 
&gt; Stack overflow during evaluation (looping recursion?).
&gt; 
&gt; So does:
&gt; x @ [] ;;
&gt; 
&gt; You can work around this like:
&gt; 
&gt; let append' a b =
&gt;    List.rev_append (List.rev a) b
&gt; ;;
&gt; 
&gt; Since both rev_append and rev are tail recursive (looping) and not 
&gt; recursive, this works.  But some ad-hoc testing says that 
&gt; this method is 
&gt; about 50% slower than normal append for lists short enough 
&gt; not to abort.
&gt; 
&gt; Thinking about this, I realized that my code is doing stuff 
&gt; like this all over the place.  I'm basically doing sparse 
&gt; vector/matrix stuff, handling
&gt; (effectively) (colno * value) list for vectors, and (rowno * 
&gt; vector) list for matrix.  And I may be hitting lists long 
&gt; enough to trip the problem.
&gt; 
&gt; Which means I'm currently doing a lot of recursion of the form:
&gt; 
&gt; let rec foo x = 
&gt;    match x with
&gt;        [] -&gt; []
&gt;        | head :: tail -&gt; (expr head) :: (foo tail)
&gt; ;;
&gt; 
&gt; for various complexities.  And it has occured to me that all of these 
&gt; forms *should* be optimizable into loops.  The general case 
&gt; would work 
&gt; something like this in C:
&gt; 
&gt; struct list_t {
&gt;     void * datum;
&gt;     struct list_t * next_p;
&gt; }
&gt; 
&gt; struct list_t * foo (struct list_t * x) {
&gt;     struct list_t * retval = NULL;
&gt;     struct list_t ** ptr_pp = &amp;retval;
&gt; 
&gt;     while (x != NULL) {
&gt;         struct list_t * temp = alloc(sizeof(struct list_t));
&gt;         *ptr_pp = temp;
&gt;         temp-&gt;datum = expr(x-&gt;datum);
&gt;         temp-&gt;next_p = NULL; /* be nice to the GC */
&gt;         ptr_pp = &amp;(temp-&gt;next_p);
&gt;         x = x-&gt;next_p;
&gt;     }
&gt;     return retval;
&gt; }
&gt; 
&gt; If expr() returned a list, the only change necessary would be 
&gt; to find the 
&gt; end of the list before moving on, like:
&gt; 
&gt; struct list_t * foo (struct list_t * x) {
&gt;     struct list_t * retval = NULL;
&gt;     struct list_t ** ptr_pp = &amp;retval;
&gt; 
&gt;     while (x != NULL) {
&gt;         *ptr_p = expr(x-&gt;datum); /* expr allocates the list */
&gt;         /* We assume the last element of the list expr() returned has
&gt;          * NULL for next_p.
&gt;          */
&gt;         while (*ptr_p != NULL) {
&gt;            ptr_p = &amp;((*ptr_p)-&gt;next_p);
&gt;         }
&gt;         x = x-&gt;next_p;
&gt;     }
&gt;     return retval;
&gt; }
&gt; 
&gt; Rather than just looking at making @ an inline C function, I 
&gt; think we (the 
&gt; Ocaml community) should be looking at adding this more general 
&gt; optimization in.
&gt; 
&gt; So now we get to my two questions:
&gt; a) is anyone working on this/intending to work on this RSN?
&gt; b) if the answer to (a) is no, can anyone give me some 
&gt; pointers on where 
&gt; to start looking at code, so I can add it in?
&gt; 
&gt; Brian
&gt; 
&gt; 
&gt; -------------------
&gt; To unsubscribe, mail caml-list-request@inria.fr Archives: 
http://caml.inria.fr Bug reports: http://caml.inria.fr/bin/caml-bugs
FAQ: http://caml.inria.fr/FAQ/ Beginner's list:
http://groups.yahoo.com/group/ocaml_beginners
-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners

</contents>

</message>

