5 ms·
> There is a difference between Racket and Scheme AFAIK the Scheme standard doesn't specify either behaviour. So, with regards to the standard both Racket and
by pflanze 6y ago
> There is a difference between Racket and Scheme
AFAIK the Scheme standard doesn't specify either behaviour. So, with regards to the standard both Racket and other Scheme implementations are free to implement this in whichever way they prefer. And the Scheme implementations that I'm using (Gambit-C, Chicken and Guile) all work the same as Racket. I only know of Bigloo (of about 10 years ago, maybe it changed?) as a Scheme implementation that uses the machine stack to implement Scheme continuation frames, and Bigloo (again back then) doesn't (didn't?) implement call/cc efficiently either. Arguably to implement the Scheme standard including call/cc efficiently the machine stack can't be used, thus any 'proper' Scheme implementation will behave like Racket.
I've written lots of non-Racket Scheme code and my code always assumes that it won't run out of stack before running out of heap. Some Scheme implementations allocate stack frames more efficiently than cons cells thus the straight-forward solution (recursion, not iteration then reversion) is also the more efficient one.
There is a tendency of claiming Racket is somehow fundamentally different from Scheme which sometimes feels a bit like a racket. I'm not opposed to Racket but think it would be better to take it as what it is, Scheme plus extensions and tooling, which most other Scheme implementations are as well. Racket may be doing that more extensively but I think it calling itself a different language should primarily be understood as a marketing ploy, or maybe as a move to justify moving ahead with own ideas without caring about the rest of the Scheme community.
- soegaard 6y agoI agree that some Scheme implementations have the same guarantee - it's not in the Scheme standard though (as far as I know), which makes it difficult to rely on, if you are programming to the spec. It is difficult to use the machine stack and have a fast call/cc. But I think Chez Scheme proves it's possible.
- pflanze 6y ago> it's not in the Scheme standard though (as far as I know), which makes it difficult to rely on, if you are programming to the spec. If you want to have code work everywhere and thus code defensively, yes. Of course you're not coding defensively when coding for Racket, either. But I guess I may have misunderstood you--Racket simply gives you a guarantee; as do some (other) Scheme implementations, so you get the same benefit with some/many other Scheme implementations as well--but even those "differ from Scheme (the standard)", by giving such a guarantee outside of the standard. It's not "Racket vs. Scheme implementations", it's "the (Racket|Scheme) implementations vs. Scheme (the standard)". Apologies then for my inappropriate rant about false claims. > It is difficult to use the machine stack and have a fast call/cc. But I think Chez Scheme proves it's possible. Chez doesn't seem to be using the machine stack either. I've tested with this code and "ulimit -s 1000" on Linux and it runs fine: (define (conc a b) (if (null? a) b (cons (car a) (conc (cdr a) b)))) (define (iot n) (if (negative? n) '() (cons n (iot (- n 1))))) (display (length (conc (iot 10000000) (iot 10000000)))) (newline) Note that it can still be using a stack built from "machine" or C style arrays as building blocks--that's what I meant with "Some Scheme implementations allocate stack frames more efficiently than cons cells". Gambit falls into this category as well. But you can't have a single uninterrupted C style array as the stack (with no copying during GC like Chicken does) and implement call/cc efficiently. So I'd still say that implementing Scheme including call/cc efficiently means moving away from the stack controlled by ulimit -s, and once that is done it's easy/natural for an implementation to also offer unbounded stacks like Racket does.
- soegaard 6y agoI think we agree: an implementation that uses a stack to make normal calls fast, needs to move/copy the stack to the heap, when the stack runs out (or when a continuation is captured). I don't know whether Chez still uses the same strategy, but a major part of Dybvig's thesis (very readable) was dedicated to explain the details of a possible implementation strategy. http://agl.cs.unm.edu/~williams/cs491/three-imp.pdf http://agl.cs.unm.edu/~williams/cs491/three-imp.pdf