Delimited continuation

In programming languages, a delimited continuation, composable continuation or partial continuation, is a "slice" of a continuation frame that has been reified into a function. Unlike regular continuations, delimited continuations return a value, and thus may be reused and composed. Control delimiters, the basis of delimited continuations, were introduced by Matthias Felleisen in 1988 though early allusions to composable and delimited continuations can be found in Carolyn Talcott's Stanford 1984 dissertation, Felleisen et al., Felleisen's 1987 dissertation, and algorithms for functional backtracking, e.g., for pattern matching, for parsing, in the Algebraic Logic Functional programming language, and in the functional implementations of Prolog where the failure continuation is often kept implicit and the reason of being for the success continuation is that it is composable.

History
Delimited continuations were first introduced by Felleisen in 1988 with an operator called $$\mathcal{F}$$, first introduced in a tech report in 1987, along with a prompt construct $$\#$$. The operator was designed to be a generalization of control operators that had been described in the literature such as  from Scheme, ISWIM's J operator, John C. Reynolds'   operator, and others. Subsequently, many competing delimited control operators were invented by the programming languages research community such as  and ,   and  ,  ,  , and others.

Examples
Various operators for delimited continuations have been proposed in the research literature.

One independent proposal is based on continuation-passing style (CPS) -- i.e., not on continuation frames—and offers two control operators,  and , that give rise to static rather than to dynamic delimited continuations. The  operator sets the limit for the continuation while the   operator captures or reifies the current continuation up to the innermost enclosing. For example, consider the following snippet in Scheme:

The  delimits the continuation that   captures (named by   in this example). When this snippet is executed, the use of  will bind   to the continuation   where   represents the part of the computation that is to be filled with a value. This continuation directly corresponds to the code that surrounds the  up to the. Because the body of shift (i.e., ) immediately invokes the continuation, this code is equivalent to the following:

In general, these operators can encode more interesting behavior by, for example, returning the captured continuation  as a value or invoking   multiple times. The  operator passes the captured continuation   to the code in its body, which can either invoke it, produce it as a result, or ignore it entirely. Whatever result that  produces is provided to the innermost , discarding the continuation in between the   and. However, if the continuation is invoked, then it effectively re-installs the continuation after returning to the. When the entire computation within  is completed, the result is returned by the delimited continuation. For example, in this Scheme code: whenever  invokes ,   is evaluated and returned.

This is equivalent to the following: Furthermore, once the entire computation within  is completed, the continuation is discarded, and execution restarts outside. Therefore,

invokes  first (which returns 8), and then   (which returns 16). At this point, the  expression has terminated, and the rest of the   expression is discarded. Therefore, the final result is 16.

Everything that happens outside the  expression is hidden, i.e. not influenced by the control transfer. For example, this returns 17:

Delimited continuations were first described independently by Felleisen et al. and Johnson. They have since been used in a large number of domains, particularly in defining new control operators; see Queinnec for a survey.

Let's take a look at a more complicated example. Let  be the empty list:

The context captured by  is , where   is the hole where  's parameter will be injected. The first call of  inside   evaluates to this context with   =   replacing the hole, so the value of   is   =. The body of, namely   =  , becomes the overall value of the   expression as the final result.

Making this example more complicated, add a line:

If we comment out the first, we already know the result, it is  ; so we can as well rewrite the expression like this:

This is pretty familiar, and can be rewritten as, that is,.

We can define  using this trick:

(define (yield x) (shift k (cons x (k (void)))))

and use it in building lists:

If we replace  with , we can build lazy streams: We can generalize this and convert lists to stream, in one fell swoop: In a more complicated example below the continuation can be safely wrapped into a body of a lambda, and be used as such: The part between  and   includes control functions like   and  ; this is impossible to rephrase using lambdas.

Delimited continuations are also useful in linguistics: see Continuations in linguistics for details.

A worked-out illustration of the idiom: the generalized curry function
The generalized curry function is given an uncurried function  and its arity (say, 3), and it returns the value of. This example is due to Olivier Danvy and was worked out in the mid-1980s.

Here is a unit-test function to illustrate what the generalized curry function is expected to do: These unit tests verify whether currying the variadic function  into an n-ary curried function and applying the result to n arguments yields the same result as applying   to these n arguments, for n = 0, 1, 2, 3, and 4.

The following recursive function is accumulator-based and eventually reverses the accumulator before applying the given uncurried function. In each instance of the induction step, the function  is explicitly applied to an argument in the curried application:

For example, evaluating reduces to evaluating which reduces to evaluating which beta-reduces to evaluating which reduces to evaluating which beta-reduces to evaluating which reduces to evaluating which reduces to evaluating which is equivalent to which delta-reduces to the result,.

The following recursive function is continuation-based and involves no list reversal. Likewise, in each instance of the induction step, the function  is explicitly applied to an argument in the curried application:

So evaluating reduces to evaluating which reduces to evaluating which beta-reduces to evaluating which reduces to evaluating which beta-reduces to evaluating which reduces to evaluating which beta-reduces to evaluating which beta-reduces to evaluating which beta-reduces to evaluating which is equivalent to which delta-reduces to the result,.

The following recursive function,, is the direct-style counterpart of   and features the   idiom, using Andrzej Filinski's implementation of shift and reset in terms of a global mutable cell and of. In each instance of the induction step, the continuation abstraction is implicitly applied to an argument in the curried application:

The heart of the matter is the observational equivalence between and where  is fresh and the ellipses represent a pure context, i.e., one without control effects.

So evaluating reduces to evaluating which reduces to evaluating which is observationally equivalent to which beta-reduces to evaluating which reduces to evaluating which is observationally equivalent to which beta-reduces to evaluating which reduces to evaluating which is equivalent to which delta-reduces to evaluating which yields the result,.

The definition of  also illustrates static delimited continuations. This static extent needs to be explicitly encoded if one wants to use and :