sâmbătă, 23 ianuarie 2010

On continuations...

As it turns out, continuations have indefinite extent in scheme. Once a continuation is captured, it can be (re-)entered again and again, as long as a reference to it exists. I was afraid of that.

In terms of implementation, having continuations requires two things: the ability to save the current control state of the program in a continuation object (known as reification), and the ability to restore it when the continuation is applied (invoked).

This wouldn't be too complicated, if only for the fact that the C interpreter stack is part of the "current control state". It will be unwound and rewound as the interpreter runs, overwriting its contents. Therefore, it does not suffice to save only the stack top, the entire contents of the stack needs to be saved.

That is not all; say a continuation is invoked, and it happens to continue with a recursive process. This will make the C stack grow and overwrite whatever was there in the stack memory segment. Trouble is, that may well be in the context of a continuation that was captured during the initial call-with-current-continuation. The interpreter would thus need to create and switch to a fresh, new stack whenever it's capturing a continuation.

Both requirements can be met portably in the interpreter by using the POSIX getcontext/setcontext functions, which would allow using different stacks in different contexts, but I feel that both copying the stacks and keeping around largely unused stack segments is a bit much for the bootstrap interpreter. Note that continuations are supposed to be garbage collected when they are no longer referenced, and I don't have a garbage collector :-)

So, while it can be done, I'm leaving continuations out of the interpreter. Same for dynamic-wind.

Here's a paper dealing with continuations and their implementation: Representing Control in the Presence of First-Class Continuations.

As a final remark, there's an elegant unifying view of continuations in the general picture of program control flow. Every form (expression) has an implicit continuation, one that resumes execution at the next form in sequence. Returning some value from a procedure is the same as invoking an exit function (the continuation) with the value to be returned. Multiple return values are then an invocation of a continuation that accepts more arguments than the usual 1.

2 comentarii:

  1. I struggled with continuations too. My solution has always been to ignore them, but in my last attempt at making a scheme interpreter I used CPS and trampolining to make call/cc and tail calls work nicely. I also get the garbage collector for free as I used Python. My code is here:

    http://github.com/kerspoon/lipy2

    I'm impressed with how quickly you are progressing with this. Keep it up.

    RăspundețiȘtergere
  2. I wish. Macros are a bit harder and the job keeps interefering :-)

    RăspundețiȘtergere