Re: CAS, Lambda Calculus, Continuation and Functional Programming
From: Robert A Duff (bobduff_at_shell01.TheWorld.com)
Date: 03/19/05
- Previous message: Dave: "University License fees are short sighted of Wolfram Research"
- In reply to: Joachim Durchholz: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Next in thread: Joachim Durchholz: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Reply: Joachim Durchholz: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Reply: Andreas Rossberg: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Reply: John Creighton: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Messages sorted by: [ date ] [ thread ]
Date: 18 Mar 2005 20:55:15 -0500
Joachim Durchholz <jo@durchholz.org> writes:
> Robert A Duff wrote:
>
> > Joachim Durchholz <jo@durchholz.org> writes:
> >
> >>> Is there anything that would
> >>> prohibit using the same optimizations in an imperative language.
> >>
> >>Partly. Imperative aspects of a language may require global program
> >>analysis to make sure that a tail call can indeed be eliminated, and
> >>that makes tail call elimination less attractive for compiler writers.
> >>I don't recall the full range of things that can prevent tail call
> >>elimination, but the two that I do recall are exception handling and
> >>setjmp/getjmp. I dimly recall that there were also issues with
> >>destructors in C++, but I may be confusing things here.
> > I don't know why exception handling should prevent tail-call
> > elimination. Would someone care to enlighten me?
> > Setjmp/longjmp is similar to exception handling. And destructors
> > require something like an implicit exception handler -- when an
> > exception occurs, catch it, call the destructor, and then re-raise the
> > same exception. So these all seem like the same issue.
>
> On second thinking, I recalled what the issue was.
>
> In all cases, there's some implicit action done in a function. Those
> that catch exceptions must unwind the exception catching machinery,
> setjmp places data on the stack that must be unwound at longjmp or
> return time, and if a local object is constructed, it must be destructed
> on function exit.
>
> These mechanisms are all nice and dandy, but they add some action after
> the end of the last explicit instruction - and the tail call isn't a
> tail call anymore.
Ah, I see, that makes sense. Thank you.
> > I think garbage collection makes tail call elimination easier,
> > and many imperative languages don't have GC, so that might be
> > part of the problem.
>
> It would eliminate the destructor problems. The rest would remain.
Well, it can eliminate destructors whose purpose is to free memory.
Destructors that (say) close file handles remain an issue.
But that's not what I meant. I meant that when you do a tail call, the
stack frame of the callee might be of different size than the stack
frame of the caller, so the tail call might need to allocate some space
on the stack. But if you have GC, and "stack" frames are actually heap
allocated, this becomes easier. True?
> > In any case, I know that some compilers for some imperative languages do
> > tail-call elimination in some cases.
>
> It has been tried on gcc. With rather limited results - the majority of
> tail calls couldn't be optimized out. Given that tail call elmination
> doesn't play nice with debuggers, it's probably not very attractive for
> the gcc folks now...
Hmm. The debugger issue. I'd like to trace back my calls, but I might
also want to trace back through 'while' loops in an imperative
language. For that matter, I might like backward execution... ;-)
> > On the other hand, some functional languages *require* tail-call
> > elimination. Is this really a formal requirement? I mean, can one
> > write a test case that fails if and only if the compiler doesn't
> > eliminate tail calls?
>
> Yes, easily. Make a function that allocates a lot of stack memory (some
> local variable with a megabyte of memory or so). Also add a counter
> that's well beyond the disk size of contemporary computers (say, a
> million - that will give a total stack requirement of a terabyte - well,
> a billion would be safer), that's decremented on each operation, and
> goes to zero finally.
> Allocation should be fast, so a local array would be best (in languages
> that support arrays).
Sorry, but I don't follow you here. (I'm being language-lawyerly in
this part, not practical.) If the thing you describe runs out of
memory, what does that prove, in a formal sense? Maybe the
implementation does not eliminate tail calls. Or, maybe, it just ran
out of memory for some other reason. How do we know?
- Bob
- Previous message: Dave: "University License fees are short sighted of Wolfram Research"
- In reply to: Joachim Durchholz: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Next in thread: Joachim Durchholz: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Reply: Joachim Durchholz: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Reply: Andreas Rossberg: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Reply: John Creighton: "Re: CAS, Lambda Calculus, Continuation and Functional Programming"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|