I guess this is a trivial question. And anyway I come up with a somewhat workable solution. I quite can't imagine that one can't do better. So here's what I use at the moment (defun get-input () "Prompt user for a number if it is a number return it otherwise return nil" (format t "Please give me a number (e for Exit) ") (let ((line (read))) (if (numberp line) line (if (y-or-n-p "Not a number, really exit?") nil (get-input)))))
A bunch of improvements come to my mind and can be implemented relativly easy, e.g replacing the test with another test the input should obey and of course other messages if the input is not what it should be.
Anyway, I think that this has been done before and I guess even in a portable way. Could you give me a hand here?
Friedrich Dominicus <Friedrich.Domini...@inka.de> wrote in message
news:87wvlv75lf.fsf@inka.de... | I guess this is a trivial question. And anyway I come up with a somewhat | workable solution. I quite can't imagine that one can't do better. So here's | what I use at the moment | (defun get-input () | "Prompt user for a number if it is a number | return it otherwise return nil" | (format t "Please give me a number (e for Exit) ") | (let ((line (read))) | (if (numberp line) | line | (if (y-or-n-p "Not a number, really exit?") | nil | (get-input))))) | | A bunch of improvements come to my mind and can be implemented relativly | easy, e.g replacing the test with another test the input should obey and of | course other messages if the input is not what it should be. | | Anyway, I think that this has been done before and I guess even in a portable | way. Could you give me a hand here? |
because you asked....
My first reaction is that recursion is not really the best idea here, it really is (logically) a "loop until" situation. But perhaps that's just a matter of style and there is no danger...
Otherwise, i don't do much "read"ing, so i can't help. I do remember with Allegro 3 having my (student) program crash if the user hit <enter> without typing anything! not the most bullet-proof design :-) (have you handled that?)
In article <87wvlv75lf....@inka.de>, Friedrich Dominicus
<Friedrich.Domini...@inka.de> wrote: > (defun get-input () > "Prompt user for a number if it is a number > return it otherwise return nil" > (format t "Please give me a number (e for Exit) ") > (let ((line (read))) > (if (numberp line) > line > (if (y-or-n-p "Not a number, really exit?") > nil > (get-input)))))
- READ neither does read a line nor does it return one, it reads the printed representation of a Lisp object and returns a corresponding Lisp object. - don't use recursion, use a loop. CL implementation don't need to be tail recursive.
> Anyway, I think that this has been done before and I guess even in a portable > way. Could you give me a hand here?
How about this? (the only thing that doesn't work is the test for "e")
Coby
(defun get-input () (let (raw-input number) (loop until number do (format t "Please Enter a Number. e will exit.~%") (setf raw-input (read-line)) (setf number (parse-integer raw-input :junk-allowed t)) (when (and (null number) (equal raw-input "e")) (return))) number)
Friedrich Dominicus <Friedrich.Domini...@inka.de> wrote in message
> RJ> In article <87wvlv75lf....@inka.de>, Friedrich Dominicus > RJ> <Friedrich.Domini...@inka.de> wrote:
> >> (defun get-input () > >> "Prompt user for a number if it is a number > >> return it otherwise return nil" > >> (format t "Please give me a number (e for Exit) ") > >> (let ((line (read))) > >> (if (numberp line) > >> line > >> (if (y-or-n-p "Not a number, really exit?") > >> nil > >> (get-input)))))
> RJ> - READ neither does read a line nor does it return one, it reads the > RJ> printed representation of a Lisp object and > RJ> returns a corresponding Lisp object. > Ok I can use read-line instead > RJ> - don't use recursion, use a loop. CL implementation don't need > RJ> to be tail recursive. > Why? I have written the same with a loop but it looks IMO more ugly. But > maybe it's just that I've written it poorly. Here it is: > (defun get-input () > "see 'get-input-recursive'" > (let ((line)) > (do ((exit nil)) > (exit line) > (format t "Please give me a number (e for Exit): ") > (setf line (read)) > (if (numberp line) > (progn > (setf exit t) > line) > (when (y-or-n-p "Not a number, really exit?") > (setf exit t) > (setf line nil))))))
> >> Anyway, I think that this has been done before and I guess even in a portable > >> way. Could you give me a hand here?
RJ> In article <87wvlv75lf....@inka.de>, Friedrich Dominicus RJ> <Friedrich.Domini...@inka.de> wrote:
>> (defun get-input () >> "Prompt user for a number if it is a number >> return it otherwise return nil" >> (format t "Please give me a number (e for Exit) ") >> (let ((line (read))) >> (if (numberp line) >> line >> (if (y-or-n-p "Not a number, really exit?") >> nil >> (get-input)))))
RJ> - READ neither does read a line nor does it return one, it reads the RJ> printed representation of a Lisp object and RJ> returns a corresponding Lisp object. Ok I can use read-line instead RJ> - don't use recursion, use a loop. CL implementation don't need RJ> to be tail recursive. Why? I have written the same with a loop but it looks IMO more ugly. But maybe it's just that I've written it poorly. Here it is: (defun get-input () "see 'get-input-recursive'" (let ((line)) (do ((exit nil)) (exit line) (format t "Please give me a number (e for Exit): ") (setf line (read)) (if (numberp line) (progn (setf exit t) line) (when (y-or-n-p "Not a number, really exit?") (setf exit t) (setf line nil))))))
>> Anyway, I think that this has been done before and I guess even in a portable >> way. Could you give me a hand here?
>>>>> "CB" == Coby Beck <cb...@mercury.bc.ca> writes:
CB> How about this? (the only thing that doesn't work is the test for "e") CB> Coby
CB> (defun get-input () CB> (let (raw-input number) CB> (loop until number CB> do (format t "Please Enter a Number. e will exit.~%") CB> (setf raw-input (read-line)) CB> (setf number (parse-integer raw-input :junk-allowed t)) CB> (when (and (null number) (equal raw-input "e")) (return))) CB> number)
* Friedrich Dominicus <Friedrich.Domini...@inka.de> | I have written the same with a loop but it looks IMO more ugly.
it's quite strange, but people who have been trained to write iteration using tail recursion tend to write the most amazingly ugly loops, and it isn't a question of lack of training in writing loops, it's conceptual. (yet another case of Scheme hurting people.)
| (defun get-input () | (let ((line)) | (do ((exit nil)) | (exit line) | (format t "Please give me a number (e for Exit): ") | (setf line (read)) | (if (numberp line) | (progn | (setf exit t) | line) | (when (y-or-n-p "Not a number, really exit?") | (setf exit t) | (setf line nil))))))
(format t "please enter a number: ") (do ((input (read nil nil nil) (read nil nil nil))) ((or (null input) (numberp input)) input) (format t "not a number, try again: "))
I'd use a different input function that read, but that's your call.
>>>>> "EN" == Erik Naggum <e...@naggum.no> writes:
EN> * Friedrich Dominicus <Friedrich.Domini...@inka.de> EN> | I have written the same with a loop but it looks IMO more ugly.
EN> it's quite strange, but people who have been trained to write iteration EN> using tail recursion tend to write the most amazingly ugly loops, and it EN> isn't a question of lack of training in writing loops, it's conceptual. EN> (yet another case of Scheme hurting people.) Thanks I take it as an compliment. Maybe I do have understand a bit of Scheme ;-)
EN> (format t "please enter a number: ") EN> (do ((input (read nil nil nil) (read nil nil nil))) EN> ((or (null input) (numberp input)) input) EN> (format t "not a number, try again: ")) I agree this is really nicer and I'll keep in under my pilow ;-)
<rainer.jos...@ision.net> wrote: >- don't use recursion, use a loop. CL implementation don't need > to be tail recursive.
Do you know why this was left out of the standard? Comming from a Scheme background, it sounds a bit weird to me...
TIA
//----------------------------------------------- // Fernando Rodriguez Romero // // frr at mindless dot com //------------------------------------------------
Fernando <spam...@must.die> writes: > On Tue, 18 Apr 2000 15:25:02 +0200, Rainer Joswig > <rainer.jos...@ision.net> wrote:
> >- don't use recursion, use a loop. CL implementation don't need > > to be tail recursive.
> Do you know why this was left out of the standard? Comming > from a Scheme background, it sounds a bit weird to me...
CL has a rich set of iterative constructs, so it was not seen necessary to require proper tail recursion. Proper tail recursion can be difficult to achieve in a number situations (witness all the `Scheme' interpreters that *don't* have proper tail recursion). At the time CL was being designed, it was rare for a lisp to be properly tail recursive, and people were getting along fine without it.
That being said, although CL isn't required to be properly tail recursive, I think *most* CL implementation have the ability to optimize tail calls between functions, and even more have the ability to optimize `self' tail calls or tail calls between internal labels expressions. You may need to (declare (optimize (speed 3))) or (declare (optimize (debug 0))) or set some internal compiler switch.
(Are there any popular CommonLisps that don't do *at least* self tail recursion?)
* Fernando <spam...@must.die> | Do you know why this was left out of the standard? Comming | from a Scheme background, it sounds a bit weird to me...
coming from a Scheme background, it should be easy for you to explain why Scheme needs it so badly and what implementation costs are associated with this requirement. then you should consider whether there are any needs in Common Lisp that are unfulfilled without it, like there would be in Scheme without it, and whether they are worth the costs. please note that proper tail recursion is closely related to first-class continuations.
incidentally, it is never productive to ask why things are "left out" of a standard unless you know that that was what happened. tail recursion is simply a non-issue in most languages, and where it matters, it had been a choice of the compiler writers and optimization settings, not a hard requirement in a standard.
that said, one reason to leave out random "good ideas" from a standard is that requiring something that nobody needs in doesn't mean people will abide by it, but it does mean they will have to start to ignore parts of the standard for _good_ reasons. this is very, very bad when it happens.
Erik Naggum <e...@naggum.no> writes: > please note that proper tail recursion is closely related to > first-class continuations.
Perhaps insofar as both are required to be in a compliant Scheme implementation but are not often specified as a requirement of any other language.
Technically, tail recursion and _first-class_ continuations have little to do with each other. An implementation that is properly tail recursive could not have first-class continuations, and an implementation that has first-class continuations need not be tail-recursive. (There are some implementation techniques that give you both, however.)
> An implementation that is properly tail > recursive could not have first-class continuations.
Meaning `a properly tail-recursive implementation *need not* have first-class continuations', not `a properly tail-recursive implementation *can not* have first-class continuations' (which is patently absurd).
* Joe Marshall <jmarsh...@alum.mit.edu> | Technically, tail recursion and _first-class_ continuations have little | to do with each other.
not so, they are conceptual twins, and it would be silly to try to specify one without the other, even if it is technically possible to ignore the other half of the conceptual solution. at the heart of the matter is whether a function call frame is heap-based or stack-based, but this is _not_ an implementation issue alone, it has to do with the whole concept of the "lifetime" of a function call. tail recursion keeps the function call alive across function entry boundaries, i.e., entering a function does not mean you have a fresh call frame. continuations keep the function call alive across function exit boundaries, i.e., exiting a function does not mean you dispose of all inferior call frames. both invalidate the trivial concept of a function call that always exist at the leaf of a call tree and which can be talked about with a concept of identity, or in brief: the function call that differs conceptually from function calls in the popular literature and programming community.
I find it interesting that several for-education languages have flirted with the heap-based call frame, but none of them have become popular, and current (very) popular hardware is also "unwilling" to make this run as fast as the much simpler stack-based call frame. even register-rich hardware has chosen to make stack-based call frames very efficient, and heap-based call frames slow and requiring a lot of manual caretaking. this is not accidental, and it should not be dismissed as "oh, that's just hardware", which is an expression of the unhealthy arrogance I see in these for-education languages.
in my view, requiring proper tail recursion and first-class continuations is evidence of an unwillingness to deal with implementation issues. in a specification, such unwillingness is just too arrogant to be a good sign, especially when it is attempted covered up or not even explained.
In article <3165662049043...@naggum.no>, Erik Naggum <e...@naggum.no> wrote:
> I find it interesting that several for-education languages have flirted > with the heap-based call frame, but none of them have become popular, and > current (very) popular hardware is also "unwilling" to make this run as > fast as the much simpler stack-based call frame. even register-rich > hardware has chosen to make stack-based call frames very efficient, and > heap-based call frames slow and requiring a lot of manual caretaking. > this is not accidental, and it should not be dismissed as "oh, that's > just hardware", which is an expression of the unhealthy arrogance I see > in these for-education languages.
As a one-time student of computer architecture, this begs the question: What choices could the CPU designer make to lessen the expense of heap-based call frames?
-- Chuck -- Chuck Fry -- Jack of all trades, master of none chu...@chucko.com (text only please) chuck...@home.com (MIME enabled) Lisp bigot, car nut, photographer, sometime guitarist and mountain biker The addresses above are real. All spammers will be reported to their ISPs.
Erik Naggum <e...@naggum.no> writes: > * Joe Marshall <jmarsh...@alum.mit.edu> > | Technically, tail recursion and _first-class_ continuations have little > | to do with each other.
> not so, they are conceptual twins, and it would be silly to try to > specify one without the other, even if it is technically possible to > ignore the other half of the conceptual solution.
Not at all. It can be quite difficult to make first-class continuations work correctly in a language; making proper tail-recursion work is far easier. Supporting first-class continuations involves addressing significant performance issues, there is usually no implementation penalty for providing proper tail recursion, and there is often a gain.
Anyone who has implemented both would agree that it makes sense to specify one without the other. In fact, there are several properly tail recursive Scheme implementations that do not have first-class continuations, and there are several properly tail-recursive CommonLisps, also without first-class continuations.
> at the heart of the > matter is whether a function call frame is heap-based or stack-based, but > this is _not_ an implementation issue alone, it has to do with the whole > concept of the "lifetime" of a function call.
This is one way of looking at it, but the notion of a `call frame' and whether it is `heap-based' or `stack-based' is very much implementation.
Consider looking at it from a denotational semantic viewpoint. When you do this you will notice that first-class continuations are explicitly modeled by reifying the implicit interpreter continuation into a denotable value. Tail recursion doesn't appear *at all* in the denotational equations.
If you cannot reify a continuation, you can prove that the lifetime of the continuation is no shorter than the lifetime of its children, thus when you implement your language, you can allocate your continuations in a stack like manner.
What about tail recursion? It doesn't enter into the denotational semantics because it has no semantic meaning. It is purely an implementation decision to ensure that you don't needlessly nest continuations. If the stack were of infinite size, tail recursion would be unnecessary.
> tail recursion keeps the > function call alive across function entry boundaries, i.e., entering a > function does not mean you have a fresh call frame.
I'm not sure what you mean by `alive' here, but it seems you are conflating two orthogonal issues. An implementation may `re-use' the topmost stack frame to achieve tail recursion, but you are in a new body of code, with new arguments. The only thing being `kept alive' is the stack pointer, but the stack pointer is often re-used by various functions.
Tail recursion involves freeing the current stack frame when a call to another function will supply the value to be returned from this call. i.e., rather than leaving the stack frame on the stack in sort of a zombie state (it does nothing but pop itself when returned to), we dispose of the frame immediately.
There are a few mechanisms by which you might do this: if you have a stack, you can pop it and immediately re-use it, if you have a heap, you could immediately put the frame on the free-list, or you could abandon the frame.
But the presence of tail recursion doesn't invalidate the notion of stack allocation: Every frame is managed in a last-in/first-out manner.
> continuations keep > the function call alive across function exit boundaries, i.e., exiting a > function does not mean you dispose of all inferior call frames.
Yes. This changes your call-record allocation from stack-like to heap like. Some implementations achieve this by copying the stack, others just punt and keep the continuations in the heap.
> both > invalidate the trivial concept of a function call that always exist at > the leaf of a call tree and which can be talked about with a concept of > identity, or in brief: the function call that differs conceptually from > function calls in the popular literature and programming community.
> I find it interesting that several for-education languages have flirted > with the heap-based call frame, but none of them have become popular, and > current (very) popular hardware is also "unwilling" to make this run as > fast as the much simpler stack-based call frame.
Bill Rozas and Jim Miller showed that stack-allocation is simply faster than heap allocation and it is worthwhile for the compiler to use stack-based call frames.
> even register-rich > hardware has chosen to make stack-based call frames very efficient, and > heap-based call frames slow and requiring a lot of manual caretaking. > this is not accidental, and it should not be dismissed as "oh, that's > just hardware", which is an expression of the unhealthy arrogance I see > in these for-education languages.
Actually, using stack-based call frames requires *more* care than using a heap based system. This is the primary reason many educational implementations just punt on using the stack. The heap is fast enough and is a lot simpler to manage.
I should point out that with the right hardware, stack-oriented tail-recursion can be made incredibly fast.
> in my view, requiring proper tail recursion and first-class continuations > is evidence of an unwillingness to deal with implementation issues. in a > specification, such unwillingness is just too arrogant to be a good sign, > especially when it is attempted covered up or not even explained.
I'd be happy to explain the rationale behind any facet of either. -- ~jrm
>* Joe Marshall <jmarsh...@alum.mit.edu> >| Technically, tail recursion and _first-class_ continuations have little >| to do with each other.
> not so, they are conceptual twins, and it would be silly to try to > specify one without the other, even if it is technically possible to > ignore the other half of the conceptual solution. at the heart of the > matter is whether a function call frame is heap-based or stack-based, but > this is _not_ an implementation issue alone, it has to do with the whole > concept of the "lifetime" of a function call. ...
> I find it interesting that several for-education languages have flirted > with the heap-based call frame, but none of them have become popular, and > current (very) popular hardware is also "unwilling" to make this run as > fast as the much simpler stack-based call frame. even register-rich > hardware has chosen to make stack-based call frames very efficient, and > heap-based call frames slow and requiring a lot of manual caretaking. > this is not accidental, and it should not be dismissed as "oh, that's > just hardware", which is an expression of the unhealthy arrogance I see > in these for-education languages.
But tail-call optimization doesn't suffer from this arrogance. Quite to the contrary, it is more efficient use of the popular stack-based call frame in current, popular hardware.
> in my view, requiring proper tail recursion and first-class continuations > is evidence of an unwillingness to deal with implementation issues. in a > specification, such unwillingness is just too arrogant to be a good sign, > especially when it is attempted covered up or not even explained.
Again, I don't see how tail-call optimization can be tarred with the same brush as first-class continuations in this regard. TCO is precisely a willingness to deal with implementation issues. In fact, I've known semanticists to express dismay that TCO deals with "grubby" implementation choices.
>Again, I don't see how tail-call optimization >can be tarred with the same brush as first-class >continuations in this regard. TCO is precisely a >willingness to deal with implementation issues. In >fact, I've known semanticists to express dismay that >TCO deals with "grubby" implementation choices.
TCO is more than just an implementation detail, as it has an impact on application design. If you know that you can depend on TCO, you can write tail-recursive programs, safe in the knowledge that they won't complain of stack overflow on any proper implementation. If the language doesn't guarantee TCO, and your application needs to deal with very large data sets, you will probably have to write it iteratively, even though recursion might be the more natural style.
This is the reason Scheme requires TCO -- the designers wanted programmers to be able to express iteration using recursive syntax, and didn't want the traditional limits of recursion to apply.
-- Barry Margolin, bar...@genuity.net Genuity, Burlington, MA *** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups. Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
In article <Q2lN4.41$my3.836@burlma1-snr2>, Barry Margolin <bar...@genuity.net> wrote:
>This is the reason Scheme requires TCO [tail-call optimization] -- the >designers wanted programmers to be able to express iteration using >recursive syntax, and didn't want the traditional limits of recursion >to apply.
Knuth's "Structured Programming Using Go To Statements" listed a variety of control structures that were often useful and were not included as parts of most languages at the time --- the N-and-a-half-times loop, the state machine, the binary-tree search, and exception handling (especially abnormal loop exits), if I remember correctly.
Some of these (especially N-and-a-half-times and exception handling) have been added to languages designed since Knuth's article, but others haven't.
Tail-call optimization allows for natural expression of all of them --- indeed, any kind of control flow you like --- without paying the space penalty for recursion.
I used this ability last week to write a tokenizer and a shift-reduce parser for an APL-like language by hand, one Scheme function per state. (In retrospect, this was a stupid thing to do; my code is hard to follow, and I would be much better off with a table-driven lexer and parser from lex and yacc or some equivalent. But it was fun, and now I think I understand shift-reduce parsers.) -- <kra...@pobox.com> Kragen Sitaker <http://www.pobox.com/~kragen/> The Internet stock bubble didn't burst on 1999-11-08. Hurrah! <URL:http://www.pobox.com/~kragen/bubble.html> The power didn't go out on 2000-01-01 either. :)
In article <ug0saqgbu....@alum.mit.edu>, Joe Marshall <jmarsh...@alum.mit.edu> wrote:
>Erik Naggum <e...@naggum.no> writes: >> * Joe Marshall <jmarsh...@alum.mit.edu> >> I find it interesting that several for-education languages have flirted >> with the heap-based call frame, but none of them have become popular, and >> current (very) popular hardware is also "unwilling" to make this run as >> fast as the much simpler stack-based call frame.
>Bill Rozas and Jim Miller showed that stack-allocation is simply >faster than heap allocation and it is worthwhile for the compiler to >use stack-based call frames.
Do you have a URL for a paper on this topic? A casual search for their names doesn't turn up anything.
I'd like to point out that each step of the Baeza-Yates string search involves ANDing many pairs of bits, which is inherently more computation than each step of the Knuth-Morris-Pratt algorithm (which only requires running a simple state machine). But the Baeza-Yates algorithm runs at very close to the same speed on modern hardware (well, most computers, past and present) because that hardware is good at ANDing many pairs of bits in parallel for reasons unrelated to Baeza-Yates string searching.
Likewise, floating-point addition is far more complex --- and inherently slower --- than integer addition. But modern hardware has huge floating-point units to speed up the floating-point addition, which make it nearly as fast as integer addition.
"Inherently slower" and "actually slower" can apparently have quite a lot of distance between them when Intel and Sun spend lots of money making inherently slower things fast. :) -- <kra...@pobox.com> Kragen Sitaker <http://www.pobox.com/~kragen/> The Internet stock bubble didn't burst on 1999-11-08. Hurrah! <URL:http://www.pobox.com/~kragen/bubble.html> The power didn't go out on 2000-01-01 either. :)
* d...@goldshoe.gte.com (Dorai Sitaram) | But tail-call optimization doesn't suffer from this arrogance. Quite to | the contrary, it is more efficient use of the popular stack-based call | frame in current, popular hardware.
I have looked around at implementations, and what I have found is that the old call-frame is basically unwound to the exact same point where a return from the function would occur, then a jump to the new function takes place instead of a call, and a new call frame is set up, just as if it were a normal function call. the savings is realized in that the depth of the stack is not increased, but other than that, nothing, and there is much loss to go with this gain: information about the caller no longer exists.
| Again, I don't see how tail-call optimization can be tarred with the same | brush as first-class continuations in this regard. TCO is precisely a | willingness to deal with implementation issues. In fact, I've known | semanticists to express dismay that TCO deals with "grubby" | implementation choices.
the point I'm trying to get across is that _requiring_ proper tail recursion is different from _optimizing_ for tail calls as an option. the requirement is very much a semantic issue. I'm all for optimizing tail calls when _I_ want to, and can make an informed choice. I'm against a requirement. please understand the difference.
* Joe Marshall <jmarsh...@alum.mit.edu> | This is one way of looking at it, but the notion of a `call frame' and | whether it is `heap-based' or `stack-based' is very much implementation.
I also said "this is not an implementation issue _alone_". therefore, I would appreciate if you argued against the semantic issues that I think exist in the design (and requirements) of both of these mechanisms.
| Consider looking at it from a denotational semantic viewpoint. ... Tail | recursion doesn't appear *at all* in the denotational equations.
function calls don't appear as such in denotational equations, either, so that's really no surprise.
rewriting a self-tail call to a jump affects recursion. _requiring_ all tail function calls to be jumps affects the entire system adversely, and does affect the semantics of the language, even if it should vanish along with many other important issues in denotational semantics.
| If the stack were of infinite size, tail recursion would be unnecessary.
unfortunately, language design has to be performed in the real world. contrary to popular belief in some quarters, programming language design is not pure mathematics. there are _severe_ constraints on what we can do, and programming language pragmatics do enter the picture. there are times when you can ignore these issues to great benefit, and there are times when you can't lest you do something terribly stupid. confusing these times is perhaps the worst thing you can do when you design a language. I maintain that Scheme does exactly that with both the proper tail call _requirement_ and with the continuations, for the same reason: they have a different function call notion than other languages.
in my view, it doesn't make much sense to _require_ tail call recursion unless you do something that would otherwise make this expensive to add as an obvious option. the reason is that there is a huge difference between a self-tail (recursive) call and a normal call, but a requirement must make them behave identically. it would make _much_ more sense to require only that self-tail calls be syntactic sugar for a loop.
* chu...@best.com (Chuck Fry) | As a one-time student of computer architecture, this begs the question: | What choices could the CPU designer make to lessen the expense of | heap-based call frames?
predictive cache line acquisition in the heap allocation direction. the stack is fast because it's nearly always in the fastest cache. if it weren't, it would be disastrously slow on modern hardware.
Erik Naggum <e...@naggum.no> writes: > * chu...@best.com (Chuck Fry) > | As a one-time student of computer architecture, this begs the question: > | What choices could the CPU designer make to lessen the expense of > | heap-based call frames?
> predictive cache line acquisition in the heap allocation direction.
How do you mean? The UltraSparc II and Athlon's and the like has prediction instructions already.