Pascal Costanza <pc@p-cos.net> wrote:
+---------------
| Joe Marshall wrote:
| > But the advantage of tail calls is that they are more general than
| > a plain GOTO. You can trivially emulate a GOTO by tail calls that
| > don't pass any arguments, but you have to come up with some
| > sort of ad-hoc convention for passing arguments if you want to
| > emulate tail-calls with GOTO. ...
|
| I am not convinced that GO doesn't have any advantages over tail calls.
| One thing that's good about GO is that you can both have invocation of
| GO and go tags in arbitrary places within a tagbody. So you can write
| code like this:
|
| (tagbody
| :tag1 ...
| (when foo (go :tag3))
| ... ;; fall
| :tag2 ... ;; through
| (unless bar (go :tag1))
| ...
| :tag3 ...
| (when baz (go :tag1)))
|
| The following observations are interesting:
|
| - Code "covered" by a label can just continue to execute
| into the next part (see the part marked as "fall through").
+---------------
You can do exactly the same thing with tail calls [at least in
those CLs providing them] by using LABELS instead of TAGBODY, though
you sometimes need to wrap the "GO"s in (RETURN-FROM here (there))
to convert them into true tail calls:
(labels (
(tag1 ()
...
(when foo (return-from tag1 (tag3)))
...
(tag2)) ; "fall through"
(tag2 ()
...
(unless bar (return-from tag2 (tag1)))
...
(tag3)) ; "fall through"
(tag3 ()
...
(unless bar (return-from tag2 (tag1)))
...
(when baz (tag1)))))
+---------------
| - We can conditional jumps anywhere in the code. These jumps don't
| have to be in tail position, but nevertheless don't grow the stack.(!
| You don't have to rearrange you code such that such jumps are in
| tail position.
+---------------
As demonstrated above, provided your LABELS routine don't do their
"jumps" from inside some binding form that *precludes* tail calls
[such as binding a dynamic variable or a CATCH or HANDLER-{CASE,BIND}
or UNWIND-PROTECT], you can turn any call into a tail-call by simply
wrapping it in (RETURN-FROM here (there)) -- no need to "rearrange"
your code more than that very-local amount.
+---------------
| Of course, one could try to come up with some extension of such a
| GO mechanism where the labels "receive" arguments and GO can pass
| arguments:
+---------------
As demonstrated above, CL already has such: LABELS.
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607