> On Aug 13, 2021, at 1:06 AM, Arthur A. Gleckler <xxxxxx@speechcode.com> wrote:
>
> Scheme Request for Implementation 226,
> "Control Features,"
> by Marc Nieper-Wißkirchen,
> is now available for discussion.
>
> Its draft and an archive of the ongoing discussion are available at https://srfi.schemers.org/srfi-226/.
>
> You can join the discussion of the draft by filling out the subscription form on that page.
>
> You can contribute a message to the discussion by sending it to xxxxxx@srfi.schemers.org.
>
> Here's the abstract:
>
> This SRFI defines a rich set of control operators for the Scheme programming language, including the venerable call/cc (call-with-current-continuation). The set of operators was highly influenced by the control operators provided by Racket.
>
> Continuations can be delimited by continuation prompts, and all continuations become delimited continuations, at the latest by the default prompt at the start of each thread. Moreover, continuations are divided into composable and non-composable continuations, which can be captured and reinstated.
>
> To investigate continuations, this SRFI supports continuation marks and offers operators to set and retrieve them. Moreover, this SRFI defines clear semantics of exceptions, parameter objects, promises, and threads consistent with the other concepts defined here.
>
> Regards,
>
>
> SRFI Editor
>
I’ll have more to say about this SRFI when I get the time to read through it carefully. One thing did catch my attention on skimming it, the extension to the signature of the procedures call-with-current-continuation and call/cc that take an optional second argument:
(call-with-current-continuation proc)
(call-with-current-continuation proc prompt-tag)
(call/cc proc)
(call/cc proc prompt-tag)
A different name for the 2 argument variants should be used.
Gambit has a performance related extension to those procedures that is incompatible with the one proposed. Here is an explanation of this extension. In Gambit the signature is:
(call/cc proc . other-args)
In other words you can pass any number of arguments to call/cc and the first must be a procedure. The procedure proc will be called with as many arguments as were passed to call/cc. The first is the continuation, and the others are the arguments passed as other-args in the same order. This can be implemented efficiently by replacing (on the stack, registers, etc) the proc parameter by the captured continuation (leaving the other parameters unchanged) and then tail-calling proc without changing the argument count.
Why is this useful? It can be used to avoid the closure creation using a form of lambda-lifting in the frequent case where proc is a lambda expression. For example:
(define (f x)
(call/cc (lambda (k) (g k x))))
Here a closure is created for the lambda expression to capture the value of the free variable x. This closure is immediately consumed by call/cc and becomes garbage.
The Gambit compiler transforms the above code using a simple form of lambda lifting:
(define (f x)
(call/cc (lambda (k x) (g k x)) x))
This avoids the creation of the closure and puts less pressure on the GC. The programmer can also write code that uses this “lambda-lifting” extension which is useful in the cases where the proc parameter is not a lambda expression and the programmer knows the origin of the procedure that will be passed to call/cc.
Note that a compiler can use the same closure avoidance approach for other procedures that take a procedure parameter that is frequently a lambda expression such as the R7RS with-input-from-file, with-output-to-file, and call-with-… . This can greatly improve the performance of code written in “thunk passing” style.
This transformation no longer works when optional parameters are added like in the proposed spec for call/cc. I suggest that the 2 parameter version of call/cc be renamed to call/cc/prompt, call/cc-prompt, prompt-call/cc or something like that.
Marc