If you generalize labels so that they become first class, then call/cc can be written in terms of goto. http://ssp.impulsetrain.com/goto.html
(And another way to do it is to simply allocate all your function call frames on the heap to begin with and not have a stack. Then call/cc is essentially free, but you need a really good incremental garbage collector because now every function call conses.)
> (let ((x 0)) (list (call/cc (lambda (f) (set! x 1) (f 2))) x))
(2 0) localhost:~/oort/examples% ../oort callcc2.nl
2
1
as expected since Oort uses heap allocated activation records.The Oort program:
typedef continuation_t = fn (p: int32) -> void;
call_cc (fun: fn(k: continuation_t) -> void) -> int32
{
retval: int32;
fun (fn (v: int32) -> void {
retval = v;
goto current_continuation;
});
// If fun returns without calling the continuation,
// then just return 0
return 0;
@current_continuation:
return retval;
}
x: int32 = 0;
print call_cc (fn (k: continuation_t) {
x = 1;
k (2);
});
print x;