Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Tail recursion & CL
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  Messages 26 - 50 of 231 - Collapse all  -  Translate all to Translated (View all originals) < Older  Newer >
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Thomas F. Burdick  
View profile  
 More options Sep 19 2001, 3:08 pm
Newsgroups: comp.lang.lisp
From: t...@famine.OCF.Berkeley.EDU (Thomas F. Burdick)
Date: 19 Sep 2001 12:08:03 -0700
Local: Wed, Sep 19 2001 3:08 pm
Subject: Re: Tail recursion & CL

Juliusz Chroboczek <j...@pps.jussieu.fr> writes:
> >> Obviously, tail recursion elimination is more than a mere
> >> optimisation.

> GM> So write a macro.

> Gareth,

> You're missing my point.  I know there are other ways.  I know half a
> dozen techniques for implementing FSMs.

> My point is that I like to implement them in a certain way, and that
> the Common Lisp standard allows a conforming implementation to
> mis-compile my code.  Fortunately, CMUCL doesn't take this liberty,
> which is usually good enough for me.

It doesn't mis-compile your code, it does exactly what it says it will
do: it calls the function.  I think Gareth had the right impulse,
though: write a macro.  It's just that WITH-STATE-MACHINE wasn't the
right one.  Write yourself WITH-TAILCALL-OPTIMIZATION.  I did for
Emacs when it was easier than changing my code to produce something
other than n-mutual tail-recursive code.  Though I admit to not having
ported it to CL (I just continue to hand rewrite or leave it to
CMUCL).  It's something that would have been nice to have in the
language, but since it doesn't *require* vendor support, and it's easy
enough to do yourself, it's not that big of a deal.

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Juliusz Chroboczek  
View profile  
 More options Sep 22 2001, 12:27 pm
Newsgroups: comp.lang.lisp
From: Juliusz Chroboczek <j...@pps.jussieu.fr>
Date: Sat, 22 Sep 2001 16:27:38 GMT
Local: Sat, Sep 22 2001 12:27 pm
Subject: Re: Tail recursion & CL
Barry,

I think this discussion is getting off-topic, and doesn't really apply
to the point I was trying to make.

But I enjoy nit-picking about semantics, and will gladly join you.

BM> The only reason that terminates is if there's a stack overflow.
BM> That's an implementation limitation, not part of the semantics.
BM> Nowhere in the CL specification does it require that the stack
BM> must have a limited size.

There are two ways of understanding a specification ``assuming
unbounded resources'':

(i) assuming availability of potentially unbounded resources, said
program does FOO; and

(ii) there exists a finite (but arbitrarily large) amount of resources
within which said program does FOO.

Obviously, you're thinking in terms of (i), while I'm thinking in
terms of (ii).  (Exercice for the reader: specify a class of
properties FOO such that (i) and (ii) coincide.)

BM> The virtual machine described by the standard has infinite memory,

I will grant you that most well-known formal semantic frameworks do
not deal with resource tracking at all, and therefore use model (i).
It is not clear to me, however, which model is used by the CL
standard, or whether the CL standard is explicit about the issue in
the first place.  Perhaps Kent can enlighten us?

                                        Juliusz


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Juliusz Chroboczek  
View profile  
 More options Sep 22 2001, 12:27 pm
Newsgroups: comp.lang.lisp
From: Juliusz Chroboczek <j...@pps.jussieu.fr>
Date: Sat, 22 Sep 2001 16:27:39 GMT
Local: Sat, Sep 22 2001 12:27 pm
Subject: Re: Tail recursion & CL
KP> I think in the above loop example, if I understand you (and I am
KP> not sure I do), there is termination in both cases: in one case
KP> due to a resource limitation on stack, and in the other case in a
KP> resource limitation brought by the mean time between failure of
KP> the host OS, its hardware, etc., which I assume is finite.

Fair enough.

I think we're back to a rather fundamental problem, which is that of
program equivalence.

In practical terms, would you accept a definition of program
equivalence that identifies a program which runs in constant space
with one which runs in linear space?

I think that one can fairly argue for both answers.  (``Fairly,'' in
this context, means ``without invoking Adam Smith's Invisible Appendages.'')

                                        Juliusz


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kent M Pitman  
View profile  
 More options Sep 22 2001, 2:04 pm
Newsgroups: comp.lang.lisp
From: Kent M Pitman <pit...@world.std.com>
Date: Sat, 22 Sep 2001 18:02:55 GMT
Local: Sat, Sep 22 2001 2:02 pm
Subject: Re: Tail recursion & CL

Juliusz Chroboczek <j...@pps.jussieu.fr> writes:
> KP> I think in the above loop example, if I understand you (and I am
> KP> not sure I do), there is termination in both cases: in one case
> KP> due to a resource limitation on stack, and in the other case in a
> KP> resource limitation brought by the mean time between failure of
> KP> the host OS, its hardware, etc., which I assume is finite.

> Fair enough.

> I think we're back to a rather fundamental problem, which is that of
> program equivalence.

> In practical terms, would you accept a definition of program
> equivalence that identifies a program which runs in constant space
> with one which runs in linear space?

I'm not sure what "linear space" is unless you mean "linear with
respect to some input".  Maybe (following on the subject line) you
mean "linear in the number of tail calls".  But if I understand the
question correctly, I think I think that it doesn't matter whether
it's "linear" or even "O(ackerman(n))".  What I think matters to me is
that it's O(finite_valued_fn(n)).  I distinguish O(infinity) as a
non-constant that no finite valued function can keep up with.  Put
another way, even with infinite tape on your turing machine, I think
you're not going to get to (foo) in (progn (loop) (foo)); and
therefore I think removing (loop) and letting you get to (foo) is not
a valid transformation.  On the other hand, in (progn (bar) (foo)), if
(bar) is an exprssion that will run any long but known-to-be-finite
time with no defined effects (other than memory use or other things we
don't quantify), I think I think it's ok to optimize to (progn (foo)).

I don't purport to be a mathemetician, but my understanding is that
the question of a discontinuity than a mere question of resources.
That is, a function whose value goes to infinity at a certain point is
different than "gee, that function goes off my page of graph paper"
and different even than "gee, I'll never be able to buy enough graph
paper to show where that function tops out" to the point of "If I set
out to buy graph paper sufficient to try to show where that function
tops out, I would never do anything afterward because there is no end
to it."  Also, I don't think it's the same to say "I recognize that
pursuing that purchase of graph paper is not worth doing; I'd better stop
here and do something else." (which is what I'm saying, with emphasis
on "STOP", meaning the program is done) and "I recognize that
pursuing that purchase of graph paper is not worth doing, so I'll just
blythely continue with the next step as if it didn't matter that I
skipped an instruction and I'll pretend nothing that followed was contingent
on my successful completion of the prior step" which is a very "C-language"
thing to do but which is NOT what I see Lisp as being about.

> I think that one can fairly argue for both answers.  (``Fairly,'' in
> this context, means ``without invoking Adam Smith's Invisible Appendages.'')

This reference escapes me.

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Erik Naggum  
View profile  
 More options Sep 22 2001, 2:22 pm
Newsgroups: comp.lang.lisp
From: Erik Naggum <e...@naggum.net>
Date: Sat, 22 Sep 2001 18:22:06 GMT
Local: Sat, Sep 22 2001 2:22 pm
Subject: Re: Tail recursion & CL
* Juliusz Chroboczek

> Obviously, you're thinking in terms of (i), while I'm thinking in
> terms of (ii).  (Exercice for the reader: specify a class of
> properties FOO such that (i) and (ii) coincide.)

  It seems to me that arguing about the flaws of limited memory is
  pointless when you accept limited execution time.  These two may well
  coincide if the system halts execution when it runs out of memory, as
  when it invokes the debugger on the out-of-memory condition.

  If there is no upper bound on the consumption of resources of a program,
  it is ipso facto _broken_, and no silly quibbling over which resource is
  exhausted _first_ can possibly change any semantics of said program.

  It is _typical_ that this has to come up in relation to a Scheme concept.

///
--
  Why did that stupid George W. Bush turn to Christian fundamentalism to
  fight Islamic fundamentalism?  Why use terms like "crusade", which only
  invokes fear of a repetition of that disgraceful period of Christianity
  with its _sustained_ terrorist attacks on Islam?  He is _such_ an idiot.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Juliusz Chroboczek  
View profile  
 More options Sep 22 2001, 2:40 pm
Newsgroups: comp.lang.lisp
From: Juliusz Chroboczek <j...@pps.jussieu.fr>
Date: Sat, 22 Sep 2001 18:40:28 GMT
Local: Sat, Sep 22 2001 2:40 pm
Subject: Re: Tail recursion & CL

>> In practical terms, would you accept a definition of program
>> equivalence that identifies a program which runs in constant space
>> with one which runs in linear space?

KMP> I'm not sure what "linear space" is unless you mean "linear with
KMP> respect to some input".

Given some problem with a well-defined notion of input size, and given
two (correct) programs that solve this problem, one of which does so
in bounded space, the other in linear space, can the two programs be
considered as equivalent?

I think one can argue both ways.  (Or else: the correct notion of
equivalence depends on the application.)

KMP> my understanding is that the question of a discontinuity than a
KMP> mere question of resources.

Both Barry and I have been very careful to avoid the term ``infinite''.
We were speaking of unbounded resources.

When modelling a finitary process such as deterministic computation,
infinity can only appear as the limit of an unbounded process.  Thus,
the question of whether the process is continuous cannot even be
formulated: the very assumption that leads us to introduce the notion
of infinity is that the process is continuous.

If you prefer, we were not even considering the notion of actual
infinity.  The largest (in some intuitive sense) notion we were
willing to consider was that of potentially unbounded usage of
resources: a usage that remains finite at any time, but with no a
priori bound.

>> (``Fairly,'' in this context, means ``without invoking Adam Smith's
>> Invisible Appendages.'')

KMP> This reference escapes me.

This modern form of mysticism, ``the market's invisible hand.''

                                        Juliusz


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kent M Pitman  
View profile  
 More options Sep 22 2001, 5:58 pm
Newsgroups: comp.lang.lisp
From: Kent M Pitman <pit...@world.std.com>
Date: Sat, 22 Sep 2001 21:56:55 GMT
Local: Sat, Sep 22 2001 5:56 pm
Subject: Re: Tail recursion & CL

But the issue of (progn (loop) (foo))
is not a question of unbounded resources, it's a question of
infinite resources.  (foo) will never be reached.

> When modelling a finitary process such as deterministic computation,
> infinity can only appear as the limit of an unbounded process.  Thus,
> the question of whether the process is continuous cannot even be
> formulated: the very assumption that leads us to introduce the notion
> of infinity is that the process is continuous.

I guess I'm just not mathy enough to make sense of this.  In my
parlance, (loop) is an "infinite loop".  There isn't any ambiguity
about this.  Nor is there any ambiguity that (foo) in (progn (loop) (foo))
cannot be reached.  Any application of mathematics which obscures this
quite obvious fact is either accidental or intentional obfuscation, IMO.
But whatever the motivation, it does not aid the understanding of the problem.

> If you prefer, we were not even considering the notion of actual
> infinity.

Then in my parlance, you are not addressing the form '(loop)'.

> The largest (in some intuitive sense) notion we were
> willing to consider was that of potentially unbounded usage of
> resources: a usage that remains finite at any time, but with no a
> priori bound.

This is trivially true of all computations but does not address the
"meaning" of those computations.  You don't understand infinity by walking
a ways and saying "it seems finite to me" and then walking a ways farther
and saying "it still seems finite" and so on.  You understand infinity
exactly by considering the fact that in the two step process "1. do infinite
work, then 2. do something else finite" that no matter how much you work on
step 1, you are no closer to doing step 2, and, moreover, understanding
that step 2 will never be done.  That is the definition of infinity.
That is what (progn (loop) (foo)) says.  If you have a mathematics that says
it means something else, you are using that math in the wrong place.

> >> (``Fairly,'' in this context, means ``without invoking Adam Smith's
> >> Invisible Appendages.'')

> KMP> This reference escapes me.

> This modern form of mysticism, ``the market's invisible hand.''

Hmm.

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Juliusz Chroboczek  
View profile  
 More options Sep 23 2001, 11:22 am
Newsgroups: comp.lang.lisp
From: Juliusz Chroboczek <j...@pps.jussieu.fr>
Date: Sun, 23 Sep 2001 15:22:01 GMT
Local: Sun, Sep 23 2001 11:22 am
Subject: Re: Tail recursion & CL
KMP> But the issue of (progn (loop) (foo))
KMP> is not a question of unbounded resources, it's a question of
KMP> infinite resources.  (foo) will never be reached.

Yes, we fully agree about that.  There is no such thing as an actually
infinite amount of work.  This was emphatically not the issue I was
trying to get you to comment on.

>> If you prefer, we were not even considering the notion of actual
>> infinity.

KMP> Then in my parlance, you are not addressing the form '(loop)'.

We agree about that, I am definitely not.

As you say, there is no ambiguity.  With any reasonable semantics, the
programs (loop) and (progn (loop) (error "Foo!")) are equivalent.

On the other hand, consider the following:

  (defun foo ()
    (foo))

and suppose that you compile FOO without tail-call elimination.  Does
FOO terminate?

The obvious answer is that my machine has finite memory, hence FOO
will run out of stack at some point, hence FOO terminates on my
machine.  This answer invokes a specific maximum stack size, and so is
not acceptable as part of a language definition.

The answer that the best-known formal semantic frameworks give is that
assuming a potentially unbounded stack, FOO will never run out of
resources, hence FOO doesn't terminate.  I claim that this answer is
not realistic.

Finally, you can say that, assuming any arbitrarily large but finite
amount of stack, FOO will terminate.  As FOO terminates in all finite
models, FOO terminates.  I claim that this last answer is more
realistic than the second one while avoiding mentioning a specific
amount of available resources.

The point I'm trying to make is that FOO terminates when compiled
without tail call elimination, and that FOO does not terminate if
compiled with tail call elimination.  Thus, tail call elimination is
not a mere optimisation, but a semantic feature.

And, incidentally, a feature that I miss in my favourite programming
language.

Regards,

                                        Juliusz


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Erik Naggum  
View profile  
 More options Sep 23 2001, 11:55 am
Newsgroups: comp.lang.lisp
From: Erik Naggum <e...@naggum.net>
Date: Sun, 23 Sep 2001 15:54:36 GMT
Local: Sun, Sep 23 2001 11:54 am
Subject: Re: Tail recursion & CL
* Juliusz Chroboczek <j...@pps.jussieu.fr>

> On the other hand, consider the following:

>   (defun foo ()
>     (foo))

> and suppose that you compile FOO without tail-call elimination.  Does
> FOO terminate?

  Why do you not distinguish between "terminate" and "signal an error"?

> Thus, tail call elimination is not a mere optimisation, but a semantic
> feature.

  This is just plain wrong.  Your semantic feature rests on an equivocation
  between termination and crashing.  I fail to see how this can reasonably
  be considered anything but _completely_ bogus.  What is the _value_ of a
  crash?  Rather, a crash is the antithesis of termination, because it
  _prevents_ every reasonably expectation from a termination.  The same is
  true for a non-idiotic example which takes enough time to terminate that
  it can run out of some resources, like electric power or memory or disk
  space or whatever -- hell, that might even happen immediate after it has
  _started_ running.  It is profoundly counter-productive to treat each and
  every cessation of execution the same way.  I wonder what kind of silly
  theoretical framework has found it useful to abstract away the value of a
  computation so one could study the conditions for cessation of execution
  without concern for what the computation yields.  It seems to be one of
  those useless theories that are used only to prove something that is
  wrong and that every reasonable person knows to be wrong, but which can
  be shown to be true if you accept a whole bunch of insane premises that
  have been divorced from the reality and purpose of computing.

  Again, it is typical that this discussion centers around a Scheme feature.

///
--
  Why did that stupid George W. Bush turn to Christian fundamentalism to
  fight Islamic fundamentalism?  Why use terms like "crusade", which only
  invokes fear of a repetition of that disgraceful period of Christianity
  with its _sustained_ terrorist attacks on Islam?  He is _such_ an idiot.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
jrm  
View profile  
 More options Sep 24 2001, 10:02 am
Newsgroups: comp.lang.lisp
From: j...@itasoftware.com
Date: 24 Sep 2001 10:02:40 -0400
Local: Mon, Sep 24 2001 10:02 am
Subject: Re: Tail recursion & CL

Normal order semantics are unreasonable?  First I've heard of that.

> On the other hand, consider the following:

>   (defun foo ()
>     (foo))

> and suppose that you compile FOO without tail-call elimination.  Does
> FOO terminate?

> The obvious answer is that my machine has finite memory, hence FOO
> will run out of stack at some point, hence FOO terminates on my
> machine.  This answer invokes a specific maximum stack size, and so is
> not acceptable as part of a language definition.

It also assumes that each call to (foo) consumes some amount of stack.
This is an unnecessary requirement.

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kent M Pitman  
View profile  
 More options Sep 24 2001, 10:23 am
Newsgroups: comp.lang.lisp
From: Kent M Pitman <pit...@world.std.com>
Date: Mon, 24 Sep 2001 14:21:39 GMT
Local: Mon, Sep 24 2001 10:21 am
Subject: Re: Tail recursion & CL

j...@itasoftware.com writes:
> > KMP> Then in my parlance, you are not addressing the form '(loop)'.

> > We agree about that, I am definitely not.

> > As you say, there is no ambiguity.  With any reasonable semantics, the
> > programs (loop) and (progn (loop) (error "Foo!")) are equivalent.

> Normal order semantics are unreasonable?  First I've heard of that.

I believe the context was "reasonable semantics for CL" -- i.e.,
"reasonable transcription of the semantics which are present and fixed
for CL even if not specified formally".  The absence of a formal
semantics presentation is not license to do new design.

It's been a long time since I had to deal with these.  Is "normal
order" the one where you don't have to do things in order?  If so, you
should remember that "reasonableness" is like "goodness"--it depends
on context and is not a universal property of the universe.  In CL,
evaluation works left to right, so you have to first dispense with one
form to get to the next. If you are unable to dispense with a certain
form, you're done.

> > On the other hand, consider the following:

> >   (defun foo ()
> >     (foo))

> > and suppose that you compile FOO without tail-call elimination.  Does
> > FOO terminate?

> > The obvious answer is that my machine has finite memory, hence FOO
> > will run out of stack at some point, hence FOO terminates on my
> > machine.  This answer invokes a specific maximum stack size, and so is
> > not acceptable as part of a language definition.

The language definition does not call "out of astack" a semantic
erorr but a resource limitation.  Read about the difference between
the classes SERIOUS-CONDITION and ERROR.  It is not an error to do this,
it just probably will result in a serious condition (stack resource xhausted);
though it might result also in lots of time passing and then the machine
having to be rebooted; that's less likely to get trapped but is also
a resource limitation.  Neither is a semantic error per se.

> It also assumes that each call to (foo) consumes some amount of stack.
> This is an unnecessary requirement.

It doesn't matter.  CL semantics deal neither with stack nor time, so either
of those commodities can run out and you have no control of it.  This is not
to say those issues are not important, but they are left, as a matter of
language design, to the vendor.  A vendor is not prohibited from doing
tail call elimination, they are simply not required to.

What is not left to the vendor is the right to hop over inconvenient
statements in order to get to one that is more convenient...


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
jrm  
View profile  
 More options Sep 24 2001, 12:15 pm
Newsgroups: comp.lang.lisp
From: j...@itasoftware.com
Date: 24 Sep 2001 12:15:14 -0400
Local: Mon, Sep 24 2001 12:15 pm
Subject: Re: Tail recursion & CL
Kent M Pitman <pit...@world.std.com> writes:

> j...@itasoftware.com writes:

> > > KMP> Then in my parlance, you are not addressing the form '(loop)'.

> > > We agree about that, I am definitely not.

> > > As you say, there is no ambiguity.  With any reasonable semantics, the
> > > programs (loop) and (progn (loop) (error "Foo!")) are equivalent.

> > Normal order semantics are unreasonable?  First I've heard of that.

> I believe the context was "reasonable semantics for CL" -- i.e.,
> "reasonable transcription of the semantics which are present and fixed
> for CL even if not specified formally".  

Ah, I was thrown by your use of the work `any'.

> It's been a long time since I had to deal with these.  Is "normal
> order" the one where you don't have to do things in order?  

Technically, normal order is when you reduce the leftmost reducable
redex at each step.  You can look upon this as a `lazy evaluation'
model.  When you have no more reducable redexes, you have found the
`normal form'.  Both normal order and applicative order will reduce to
the same normal form (when both reduce), but there are some
expressions for which applicative order reduction won't reduce.

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Juliusz Chroboczek  
View profile  
 More options Sep 28 2001, 6:59 pm
Newsgroups: comp.lang.lisp
From: Juliusz Chroboczek <j...@glory.dcs.ed.ac.uk>
Date: 28 Sep 2001 23:58:57 +0100
Local: Fri, Sep 28 2001 6:58 pm
Subject: Re: Tail recursion & CL
EN>   Why do you not distinguish between "terminate" and "signal an error"?

[...]

EN>   This is just plain wrong.  Your semantic feature rests on an
EN>   equivocation between termination and crashing.

No.  It rests on *distinguishing* between non-termination and
the signalling of STORAGE-CONDITION.

Suppose you identify signalling a condition and not terminating, i.e.

  (loop)

and

  (error "Foo!")

are equivalent.

Then (assuming a compositional semantics) you have to identify

  (progn (ignore-errors (loop)) t)

and

  (progn (ignore-errors (error "Foo!")) t)

If you choose to identify the latter program with T (a rather natural
hypothesis), and the former one with (LOOP), then you've just identi-
fied (LOOP) with T.  With a little more work (and some similarly
natural hypotheses), you've just identified all Lisp programs.

Not a very interesting semantics.

                                        Juliusz

P.S. Okay, I've cheated.  Whether a stack overflow generates a
STORAGE-CONDITION or causes a nuclear holocaust is ``implementation-
defined'' in ANSI Common Lisp.  Still, I think it's natural to
distinguish between a ``crash'' and non-termination.

The accepted terminology in the Semantics community, by the way, is to
include abnormal termination under the term ``termination''.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Erik Naggum  
View profile  
 More options Sep 28 2001, 7:03 pm
Newsgroups: comp.lang.lisp
From: Erik Naggum <e...@clemacs.org>
Date: Fri, 28 Sep 2001 23:03:36 GMT
Local: Fri, Sep 28 2001 7:03 pm
Subject: Re: Tail recursion & CL
* Juliusz Chroboczek

> The accepted terminology in the Semantics community, by the way, is to
> include abnormal termination under the term ``termination''.

  That seems like a very good way to cheat yourself out of a large number
  of a really hairy problems.  Cleaning up such things is not interesting.

///
--
  Why, yes, I love freedom, Mr. President, but freedom means accepting risks.
  So, no, Mr. President, I am not with you, and I am not with the terrorists.
  I would be happier if you left the airports alone and took care of all the
  cars that are a much bigger threat to my personal safety than any hijacking.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Juliusz Chroboczek  
View profile  
 More options Sep 28 2001, 7:12 pm
Newsgroups: comp.lang.lisp
From: Juliusz Chroboczek <j...@glory.dcs.ed.ac.uk>
Date: 29 Sep 2001 00:12:54 +0100
Local: Fri, Sep 28 2001 7:12 pm
Subject: Re: Tail recursion & CL
KMP> This is not to say those issues are not important, but they are
KMP> left, as a matter of language design, to the vendor.  A vendor is
KMP> not prohibited from doing tail call elimination, they are simply
KMP> not required to.

I understand that.  I wasn't complaining about the vendors' behaviour,
but about the guarantees given by the standard being too weak for my
personal programming style.

People like you have taught me to program by the book, not for the
implementation.  The lack of strong guarantees about tail-call
elimination in the book forces me to program for the implementation
(or to give up on a number of techniques that I happen to find useful).

Of course, I am not implying that you (plural) have done anything
wrong when designing ANSI Common Lisp.  I am quite willing to believe
that this was the right compromise at the time (possibly for the very
same reasons as the ones you gave recently for the omission of a MOP).

Regards,

                                        Juliusz


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kent M Pitman  
View profile  
 More options Sep 28 2001, 7:59 pm
Newsgroups: comp.lang.lisp
From: Kent M Pitman <pit...@world.std.com>
Date: Fri, 28 Sep 2001 23:59:22 GMT
Local: Fri, Sep 28 2001 7:59 pm
Subject: Re: Tail recursion & CL

Lisp needs both (i) and (ii) togetether.

> Obviously, you're thinking in terms of (i), while I'm thinking in
> terms of (ii).  (Exercice for the reader: specify a class of
> properties FOO such that (i) and (ii) coincide.)

> BM> The virtual machine described by the standard has infinite memory,

> I will grant you that most well-known formal semantic frameworks do
> not deal with resource tracking at all, and therefore use model (i).
> It is not clear to me, however, which model is used by the CL
> standard, or whether the CL standard is explicit about the issue in
> the first place.  Perhaps Kent can enlighten us?

Necessarily because the language is reflective, it uses a hybrid model
for which I'm pretty sure your semantics just doesn't apply.  The
standard is expressed in English and it is the burden of anyone who
wants to apply any out-of-band lemmas from some other domain to CL to
first show that they have a correct semantic description of the language.

We specifically chose English because it was democratic and accessible to
the programming community we needed to reach, such as myself, for example.
I am far from the "guiding force" behind CL. I was there, I had a lot of
opinions that got incorporated, and I was the "neutral editor" once votes
were taken.  But people like Steele and Gabriel were there and fully
aware of enough issues of formal semantics that they could have objected at
any time if we were too far afield.  My own personal understanding of
semantics says that something is "semantically well-formed" if I think I can
read it and understand it and implement it without ambiguity.  I'm sorry
that's probably not very scientific, but I've found it operationally
useful over the years.  The things I intuitively see as semantically
well-formed seem to be exactly the set of things the math guys are happy
describing, given that they ever take the patience to properly describe
it and don't just dive in with prefab scaffolding of some system they like
to use and hope it works in the current situation.

The system we use describes BOTH a virtual semantics in which you can recurse
indefinitely and not worry about stack, in which you can cons indefinitely
and not worry about heap, etc.  AND a practical semantics in which you can
limit these things and still be a correct implementation.  A conforming
implementation must not tell the user he has made a semantic violation if
he depends on stack to be too deep--SERIOUS-CONDITION is ok, but ERROR is
not. Ditto for consing too much, though handling that case is going to be
hard for other reasons.  Still, it doesn't make an implementation
non-conforming.

(ignore-errors (loop)) does not terminate.

neither does

(defun foo () (foo))
(ignore-errors (foo))

The latter, though, creates a resource violation in some (but not all)
implementations.  This is permitted.  And Lisp is reflective, so the
resource violation is permitted to be signaled.  It would be an unuusal
Lisp that signaled a resource violation for (ignore-errors (loop)) but
technically I think signalling a TIME-EXHAUSTED situation would be
permissible, as long as it was a serious condition and not an error.
It should not be trapped by IGNORE-ERRORS.

Lisp does allow even resource limitations to be trapped, so any formal
semantics you apply must be one that deals not only with bottom and its
infections nature compositionally, but also with some operator that can
trap bottom and keep it in check, at least some of the time.  My intuitive
sense is that this is overpowerful and probably gets messy becuase it's
got analogies to a system with both an unstoppable force and an
infinite barrier.  One has to give.  Probably it will be the unstoppable
force, since writing infinite barriers probably can't keep lisp from
stopping.  But conceptually, Lisp creates a reflective battleground in
which the struggle is permitted to take place.  And if it's uncomputable
who will win, that's too bad, because in practice it's still worth trying
to navigate this space in the name of robustness.  I would not want a weaker
language just becuase it promised more deterministic behavior.

Lisp is a hybrid of your modes (i) and (ii) above because it is intended
both to recognize an idealized semantics it may not be able to implement,
and also to accept its own limitations.  (In this way, it's probably not
that different from being religious, for those of you who are.)  It is both
trying to enforce the ideal semantics but also to still HAVE a semantics
in the case where its semantics are violated.  In this regard, it is
partly reflective.  It is not 3lisp nor some other dialect that purports
to be wholly reflective, but it plainly involves some of the complex issues
that come up in such situations, and embracing it with the same tools for
semantics that you use for other languages is not meeting it on its own
terms, I think.  Lisp has traditionally begun by trying to figure out what
it wants to do and leaving it to the theorists to catch up; the problem with
working the other way around is that you always have a language which is
limited by the knowledge of the day it was designed and only gets old from
there; Lisp continues to challenge the theorists even after its design,
which may be puzzling but I regard as appropriate.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kent M Pitman  
View profile  
 More options Sep 28 2001, 8:08 pm
Newsgroups: comp.lang.lisp
From: Kent M Pitman <pit...@world.std.com>
Date: Sat, 29 Sep 2001 00:05:58 GMT
Local: Fri, Sep 28 2001 8:05 pm
Subject: Re: Tail recursion & CL

Juliusz Chroboczek <j...@glory.dcs.ed.ac.uk> writes:
> EN>   Why do you not distinguish between "terminate" and "signal an error"?

> [...]

> EN>   This is just plain wrong.  Your semantic feature rests on an
> EN>   equivocation between termination and crashing.

> No.  It rests on *distinguishing* between non-termination and
> the signalling of STORAGE-CONDITION.

But why?  STORAGE-CONDITION merely signals a lack of resource in the
ability to wait.  It is not predictive of whether the waiting would
have done the same thing; it is utterly agnostic on the issue.  No
implementation is required to stop.  Implementations are permitted to
do tail call elimination.  

> Suppose you identify signalling a condition and not terminating, i.e.

>   (loop)

> and

>   (error "Foo!")

> are equivalent.

They don't do the same thing. There are situations in which they are they
are operationally the same and situations in which they are not.

> Then (assuming a compositional semantics) you have to identify

I don't know what a "compositional semantics" implies here--sounds
like it means "a sequence of words not included in the spec".  Would
that be a fair interpretation?  Lisp is a partly reflective language,
and error invokes the reflective mechanism, while LOOP does not.  So
there are many ways in which the two are alike and some ways in which
they are not.

>   (progn (ignore-errors (loop)) t)

> and

>   (progn (ignore-errors (error "Foo!")) t)

This is an example of how the two are not alike.

> If you choose to identify the latter program with T (a rather natural
> hypothesis), and the former one with (LOOP), then you've just identi-
> fied (LOOP) with T.  With a little more work (and some similarly
> natural hypotheses), you've just identified all Lisp programs.

I don't know what this "identified with" stuff here is, but it's not in the
language definition, so it's really just not relevant.  I see this as an
improper application of the mathy game of "deltas and epsilons" where you
have played deltas but are obliged to play epsilons.  It's your burden to
show that your reasoning conforms to the language defintiion, which is
democratically expressed in English and open to all to understand; the
language is not offered in some elitist mathy formal semantics and that
means that attempts to apply such semantics should be made only where you
can prove that it such semantics is appropriate.  That as contrasted with
Scheme where the language definition is offered in two allegedly redundant
forms, but where if there is ever a dispute a certain part of the public will
be locked out of it because they will be overwhelmed by obscure notation.
In the design of CL, we specifically addressed the idea of such redundancy
and decided it was a bad plan.

> Not a very interesting semantics.

You're welcome to conclude as you like (though you somewhat put the
lie to the claim by continuing to discuss it... sort of like someone
claiming that Jerry Springer is boring TV but tuning in every day to
watch the fist fights).  We're busy building programs are interesting,
not semantics that are interesting. Our dull semantics has not seemed
to impede that.

>                                         Juliusz

> P.S. Okay, I've cheated.  Whether a stack overflow generates a
> STORAGE-CONDITION or causes a nuclear holocaust is ``implementation-
> defined'' in ANSI Common Lisp.  Still, I think it's natural to
> distinguish between a ``crash'' and non-termination.

I don't get it.  IGNORE-ERRORS doesn't trap stack overflow and it doesn't
trap infinite loops.  They are both the same.  They are resource limitations.

ERROR is trapped because it involves a semantic violation.

> The accepted terminology in the Semantics community, by the way, is to
> include abnormal termination under the term ``termination''.

Too bad, but you are misapplying the semantics of the semantics community.
The "abnormal termination" here is due to an inability of the processor
to have the resources to supply the correct semantics.  The correct semantics
allow the program you want.  HOWEVER, a processor is considered conforming
for not having those resources.  The following is the definition of a
completely conforming common lisp processor; it's not likely to be
marketworthy, but it is allowed to claim conformance:

(defun common-lisp ()
  (write-string "Resources exhausted."))

It probably also dumps out into a killer-small hello world, by the way, for
those who like to optimize such things and worry that CL has missed that boat.

CL has the notion of an ideal semantics separate from the notion of an
implemented semantics.  I'm sorry if the semantics community doesn't
like that, but they'll just have to deal.  We describe arbitrary
precision integers but we don't require all conforming processors to
have the memory needed to house them.  We assume describe programs
that can have arbitrary stack depth but we leave it to implementations
to sort out how deep the stacks really are and whether they are
extensible.  We SAY that these are not to be identified as errors but
as resource limitations.

We say programs in CL have a meaning independent of the question of
whether processors will reliably run them.  Processors for CL are
intended to try their best to meet that meaning, but are allowed to
fail under certain cases and still be conforming.  It is specifically
left to the market to sort out whether this is worth money to buy.  We
figured that was a much better test of worthiness since in a
pluralistic society we expect there to be cases where one solution is
ok for some and not for others and vice versa...  Some people will
want implementations with tail call elimination, some won't.  I don't,
for example.  You do.  So we'll prefer different implementations.  We
can still agree on the meaning of the programs that might different in
behavior between them, though.  And we vendors can decide whose money
they want, without losing their right to claim conformance. Seems ok to
me...


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jochen Schmidt  
View profile  
 More options Sep 28 2001, 8:50 pm
Newsgroups: comp.lang.lisp
From: Jochen Schmidt <j...@dataheaven.de>
Date: Sat, 29 Sep 2001 02:47:25 +0200
Local: Fri, Sep 28 2001 8:47 pm
Subject: Re: Tail recursion & CL
If you run your (loop) example on a laptop running on batteries
you will see in not so long time that even (loop) is doomed to
"terminate" because some resource is exhausted.

bye,
Jochen

--
http://www.dataheaven.de


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Juliusz Chroboczek  
View profile  
 More options Sep 29 2001, 7:44 pm
Newsgroups: comp.lang.lisp
From: Juliusz Chroboczek <j...@pps.jussieu.fr>
Date: Sat, 29 Sep 2001 23:44:18 GMT
Local: Sat, Sep 29 2001 7:44 pm
Subject: Re: Tail recursion & CL

>> No.  It rests on *distinguishing* between non-termination and
>> the signalling of STORAGE-CONDITION.

KMP> But why?  STORAGE-CONDITION merely signals a lack of resource in
KMP> the ability to wait.  It is not predictive of whether the waiting
KMP> would have done the same thing; it is utterly agnostic on the
KMP> issue.  No implementation is required to stop.  Implementations
KMP> are permitted to do tail call elimination.

Sure.

The question is the other way around: would it make sense for a
hypothetical future standard to require that a given piece of code is
*not* allowed to signal STORAGE-CONDITION or crash?  In other words,
is there a technically correct way to *mandate* tail-call elimination
in a (hypothetical) standard of the quality of ANSI CL.

My claim is that there is; but this claim relies fundamentally on the
fact that STORAGE-CONDITION *is* different from looping.

In the rest of the discussion, you would appear to have dualised my
position: I am claiming that non-termination and signalling a
condition (or crashing) *are* different results...

>> (progn (ignore-errors (loop)) t)

>> and

>> (progn (ignore-errors (error "Foo!")) t)

KMP> This is an example of how the two are not alike.

...which you would appear to at least partly agree with.

Regards,

                                        Juliusz


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kent M Pitman  
View profile  
 More options Sep 29 2001, 11:54 pm
Newsgroups: comp.lang.lisp
From: Kent M Pitman <pit...@world.std.com>
Date: Sun, 30 Sep 2001 03:54:21 GMT
Local: Sat, Sep 29 2001 11:54 pm
Subject: Re: Tail recursion & CL

I think you're really asking me whether it is a valid thing to want
implementations to do, and I think "sure".  But if your question is
literally, as worded, "should standards be the mechanism by which this
is achieved", I'm less sure.

I will say that I have in the past advocated that the standard would
be more useful if it told you things like "the worst case time in
doing a AREF will be O(1)" vs "the worst case time in doing ELT will
be O(n) for lists of length n or O(1) for arrays".  There are places
where we've left it open and as a consequence an implementation can do
really stupid things that are baffling to users.  SET-FILE-POSITION
was discussed recently; some people expect it to be O(1) and if it's
O(n) [for n=filepos], that's pretty scary.  But the consensus was that
this should be left to an implementation.

To some extent, one might characterize my position as "there are
bigger fish to fry than tail recursion" or one might say "it's just
not consistent with the overall design to talk about memory use when
nothing really does".  You might appeal back to the "infinity" vs "finite"
argument and say it was particularly important for the tail call case;
I don't know.  I'd rather tail call elimination be under OPTIMIZE
declaration control and not a required feature of the language, so that
kind of issue would need to get factored in, too.

And then there's the practical matter that the current climate is that none
of this rises to the level of it being worth it to the community to change
the standard.  Merely opening the standard for the fixing of ANY technical
item exposes the process to the risk of major politicking; it is not allowed
to just make a work item to make a small correction under ANSI rules, I
believe.  I think you have to just open the spec for change and then other
things you didn't expect might creep in.  Stability is best maintained by
not touching it, and there's nothing now that cries out as needing fixing.

I'd almost say that if something DID come up that required fixing, ANSI would
not be the vehicle of choice to do it.

The reason I think people wanted to leave speed issues entirely out of the
standard is that the market is really better at sorting things out.  Let's
take the example of the MOP.  It's not standard either, but consensus seems
to me to be that it's ok to use because most implementations do have it.
Other things, like tail call elimination, haven't even been voluntarily
adopted by implementations even though they are allowed to.  If this came back
to ANSI and we operated as we have done in the past, the first thing that
would be asked when your hypothetical proposal to define this came to the
table would be "what is the current practice?" and the answer would be "no
one does it".  And that would immediately be translated to statements like
"sounds dicey" and "sounds like it will impose cost on all vendors that they
don't feel a need for" and "sounds like there is no call for it".

The first stage of making the change is not to look to the standard  unless
the standard forbids the change.  The first stage is to get vendors to
experiment, and then to drive the wedge by asking that code that runs in
one vendor run in another.  Best, I think, would be to operate under a switch
so that code that did this had to self-identify and other compilers could
minimally say "I don't support that option, your code will likely lose" rather
than quietly compiling the code and then losing on it at runtime...

Apparently.  :-)

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Lieven Marchand  
View profile  
 More options Sep 30 2001, 12:34 pm
Newsgroups: comp.lang.lisp
From: Lieven Marchand <m...@wyrd.be>
Date: 30 Sep 2001 13:29:19 +0200
Local: Sun, Sep 30 2001 7:29 am
Subject: Re: Tail recursion & CL

Juliusz Chroboczek <j...@pps.jussieu.fr> writes:
> The question is the other way around: would it make sense for a
> hypothetical future standard to require that a given piece of code is
> *not* allowed to signal STORAGE-CONDITION or crash?  In other words,
> is there a technically correct way to *mandate* tail-call elimination
> in a (hypothetical) standard of the quality of ANSI CL.

Defining tail call elimination is trickier than most people expect. In
fact, although Scheme has for a long time expressed the intention to
be "properly tail recursive", only the most recent report (R^5RS)
makes an attempt at defining this concept, and for the formal
definition it refers to a paper by Clinger(1998): "William D
Clinger. Proper tail recursion and space efficiency."

In the abstract of this article he says: "Proper tail recursion is not
the same as ad hoc tail call optimization in stack-based
languages. Proper tail recursion often precludes stack allocation of
variables, but yields a well-defined asymptotic space complexity that
can be relied upon by portable programs."

--
Lieven Marchand <m...@wyrd.be>
She says, "Honey, you're a Bastard of great proportion."
He says, "Darling, I plead guilty to that sin."
Cowboy Junkies -- A few simple words


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kent M Pitman  
View profile  
 More options Sep 30 2001, 2:12 pm
Newsgroups: comp.lang.lisp
From: Kent M Pitman <pit...@world.std.com>
Date: Sun, 30 Sep 2001 18:11:52 GMT
Local: Sun, Sep 30 2001 2:11 pm
Subject: Re: Tail recursion & CL

Lieven Marchand <m...@wyrd.be> writes:
> Defining tail call elimination is trickier than most people expect. In
> fact, although Scheme has for a long time expressed the intention to
> be "properly tail recursive", only the most recent report (R^5RS)
> makes an attempt at defining this concept, and for the formal
> definition it refers to a paper by Clinger(1998): "William D
> Clinger. Proper tail recursion and space efficiency." [...]

I can hear some people saying "how could it be complicated?".  For those
who are looking for at least one concrete example, I believe the following
kind of thing was raised as ambiguous even under the Scheme spec:

 (defun (factorial x n)
   (if (zerop x) n
       (let ((result (factorial (- x 1) (* x n))))
         result)))

As should be obvious, this affects the whole issue of how the language
treats variables--i.e., is it just "allowed" or is it actively "required"
to fold uses of variables, because this in turn forces implementations to
do some code analysis that they might not be prepared to do, especially in
an interpreter, the major point of which is to have lazy application of
semantics by analyzing things only locally as they are encountered; this
would effectively push an interpreter closer to a compiler, almost calling
into question whether an interpreter was even allowed.

Of course, you could just say it wasn't a tail call, but some people are
apparently offended by that because they want (let ((x y)) x) and y to be
semantically the same thing.  If introducing such bindings creates
unwanted additional effects (beyond just naming a quantity), it inhibits
the usefulness of code transformations--or, at least, makes such
transformations a lot harder to write.

[Note that I often beat people up for wanting to apply certain optimizations
that are not part of the language and complaining that they can't, but this
is different:  we're not in the context of "how do I optimize the fixed
language?" but rather "how should I define the language such that optimizations
I know of will be applicable?".]

Anyway, I hope this brief overview gives the sense that this issue of
tail call elimination isn't just a "no brainer" that can just be
dropped into the language spec trivially.  It's much easier to have an
implementation maintainer take on the responsibility because that
maintainer is financially responsible for any impact on the usability
of their own implementation.  For the language designers to make the
same choice, they have to be sensitive to revenue to implementations
they don't own, and that's a considerably bigger responsibility.  ANSI
defines away such responsibility legallyl by allowing organizations to
freely join and vote, and by requiring even minority parties that are
economically impacted to be seriously treated.  And the result of the vote
the last time around was that there was even majority concern ...


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Francois-Rene Rideau  
View profile  
 More options Sep 30 2001, 6:25 pm
Newsgroups: comp.lang.lisp
From: Francois-Rene Rideau <fare+NOS...@tunes.org>
Date: 01 Oct 2001 00:25:27 +0200
Local: Sun, Sep 30 2001 6:25 pm
Subject: Re: Tail recursion & CL

Juliusz Chroboczek <j...@pps.jussieu.fr> writes:
> The question is the other way around: would it make sense for a
> hypothetical future standard to require that a given piece of code is
> *not* allowed to signal STORAGE-CONDITION or crash?  In other words,
> is there a technically correct way to *mandate* tail-call elimination
> in a (hypothetical) standard of the quality of ANSI CL.

Why not instead have an explicit (TAIL-CALL (F X)) special form,
or otherwise two special forms (TAIL-APPLY #'F (LIST X))
and (TAIL-FUNCALL #'F X) ? It would seem much more in line with
the rest of the Common LISP tradition: if it has a special,
different meaning, then have a special, different, syntax for it,
that signals the difference.

Yours freely,

[ François-René ÐVB Rideau | Reflection&Cybernethics | http://fare.tunes.org ]
[  TUNES project for a Free Reflective Computing System  | http://tunes.org  ]
*EULA: By reading or responding to this message you agree that all my stated
opinions are correct.* "EULA" -- patent pending.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Rahul Jain  
View profile  
 More options Sep 30 2001, 9:30 pm
Newsgroups: comp.lang.lisp
From: Rahul Jain <rj...@rice.edu>
Date: 30 Sep 2001 20:23:46 -0500
Local: Sun, Sep 30 2001 9:23 pm
Subject: Re: Tail recursion & CL

Francois-Rene Rideau <fare+NOS...@tunes.org> writes:
> Why not instead have an explicit (TAIL-CALL (F X)) special form,
> or otherwise two special forms (TAIL-APPLY #'F (LIST X))
> and (TAIL-FUNCALL #'F X) ? It would seem much more in line with
> the rest of the Common LISP tradition: if it has a special,
> different meaning, then have a special, different, syntax for it,
> that signals the difference.

Because we already have DO and LOOP for that.

I suppose someone could write macros that transformed these tail-apply
and tail-funcall -containing forms into DO or LOOP forms, but that
sounds to me like part of the process of writing a compiler. :)

--
-> -/-                       - Rahul Jain -                       -\- <-
-> -\- http://linux.rice.edu/~rahul -=- mailto:rahul-j...@usa.net -/- <-
-> -/- "I never could get the hang of Thursdays." - HHGTTG by DNA -\- <-
|--|--------|--------------|----|-------------|------|---------|-----|-|
   Version 11.423.999.220020101.23.50110101.042
   (c)1996-2000, All rights reserved. Disclaimer available upon request.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Thomas F. Burdick  
View profile  
 More options Oct 1 2001, 1:22 am
Newsgroups: comp.lang.lisp
From: t...@conquest.OCF.Berkeley.EDU (Thomas F. Burdick)
Date: 30 Sep 2001 22:22:50 -0700
Local: Mon, Oct 1 2001 1:22 am
Subject: Re: Tail recursion & CL

Rahul Jain <rj...@rice.edu> writes:
> Francois-Rene Rideau <fare+NOS...@tunes.org> writes:

> > Why not instead have an explicit (TAIL-CALL (F X)) special form,
> > or otherwise two special forms (TAIL-APPLY #'F (LIST X))
> > and (TAIL-FUNCALL #'F X) ? It would seem much more in line with
> > the rest of the Common LISP tradition: if it has a special,
> > different meaning, then have a special, different, syntax for it,
> > that signals the difference.

> Because we already have DO and LOOP for that.

(defun foo (n)
  (format t "There are ~D stack frames left~%" n))

(defun my-fun (stack-frames-left)
  (if (not (zerop stack-frames-left))
      (my-fun (1- stack-frames-left))
      (tail-call (foo stack-frames-left))))

How are DO and LOOP going to help here?


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Messages 26 - 50 of 231 < Older  Newer >
« Back to Discussions « Newer topic     Older topic »