Though it kind of sucks that Tail Call Elimination is such a difficult task on the JVM.
Scheme kind of gets you thinking in a way that works iteratively, but gets expressed recursively. Its easy to read, and can make for some great optimisation without being premature.
The JVM does not really support this style of programming - despite LISP's syntax leading towards it.
I wouldn't say that it was appropriate there, either.
I really wish I could get my hands on a LISP Machine.
I love the idea of LISP being so close to the metal, but that power means some design tradeoffs.
Scheme makes sense with TCE.
I'm not sure InterLISP and the like need it - memory is limited and you work without so many of the system overheads I'm used to with modern systems. Iteration is less costly here, and that makes it easier to not need recursive design. (Which is more expensive).
In simple terms:
Why worry about blowing up a stack you don't need, when you've thought long and hard before you allocated it?
The designers argued that a million-line software (the OS + basic applications) was easier to debug/develop without having TCO everywhere. It makes stack traces useless, unless one thinks of clever ways to keep tail calls recorded, which makes it complex/tricky. The basic machine architecture is a stack machine with compact and nice instructions. Stack traces were useful then. The compiler also was not very sophisticated when it comes to optimizations.
I've long thought the right thing for Common Lisp would be to provide a way to declare sets of functions such that any tail call from one member of the set to another would be TCO'd; all other calls would push stack. This lets you write sets of mutually tail-recursive routines without forcing TCO on the entire system.
It's an entirely reasonable tradeoff, which I understand. But not having TCO is a strong negative from the language perspective, IMHO. Not an impossibly bad one, but it's really nice.
Funny enough, it seems JavaScript will get TCO before Java. JavaScript, for f*ck's sake! This will provide even more argumentative power to the people who claim JavaScript is 'Scheme in C clothes'.
However, a named let in Scheme is not a loop. Its still a lambda.
Which means you can have nested lets with TCE, and you can construct them on the fly, depending on what your needs are, usung patterns like currying.
That flexibility just doesn't work on the JVM. You can force it, but it'll be slow and horrible compared to another pattern - and I don't think a LISP should tell me how to do something. That's Python's ideology.
Scheme kind of gets you thinking in a way that works iteratively, but gets expressed recursively. Its easy to read, and can make for some great optimisation without being premature.
The JVM does not really support this style of programming - despite LISP's syntax leading towards it.