Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

An interesting discussion about the distinction between callbacks and continuations over on SO has prompted this question. By definition, a continuation is an abstract representation of the logic needed to complete a computation. In most languages this manifests as a one argument procedure to which you pass whatever value needs continued processing.

In a purely functional language (where all functions are pure and first class citizens), I would think a continuation could be entirely modeled as a function. This is, after all, how I've previously understood continuations up to this point. However, the world is full of state (sigh..) and so the general definition does not require that a continuation capture program state -- it need only encompass intent.

To help my understanding, can an example be provided in a functional language where the continuation is expressed in a more abstract way than a function? I know Scheme allows you to grab the current continuation in a first-class manner (call/cc), but even so, it seems that the one argument procedure passed to call/cc is simply given the current continuation in the form of another one argument procedure to which the call/cc'd function can apply its result.

share|improve this question
    
Perhaps the intersection of continations and defunctionalization as: continuations can be converted to data structures via defunctionalization; might be an interesting area to look at. –  Dan D. Sep 20 '13 at 8:38
    
@DanD. do you have any suggestions for interesting literature I can read? That topic sounds useful. –  David Cowden Sep 20 '13 at 8:43
    
For instance: Recycling Continuations (Sobel, Friedman) –  Dan D. Sep 20 '13 at 22:03
    
@DanD. interesting, thanks! –  David Cowden Sep 21 '13 at 1:07

2 Answers 2

up vote 7 down vote accepted

tl;dr; The type is the overarching abstraction over a continuation


A continuation is the type of its inputs and outputs

The closest thing you will find to a non-procedure based continuation is likely the continuation monad in Haskell as it is expressed as a type, for which many functions may be used to interact with the type to interrupt, resume, backtrack, et al.

You can encapsulate that closure in a type such as the Cont type in Haskell where you get the monad abstraction as a "higher level abstraction", and there are other forms of abstraction over continuations you get when you look at the continuation as a type instead of simply a procedure, for instance

  • You can take two continuations and do an alternative between them if the type follows the laws to be a monoid
  • You can abstract over the type to change the input or output types of the continuation if you encapsulate the closure in a type that abides the laws of a functor
  • You can arbitrarily and partially apply or decorate your continuation with functionality such as input validation or input conversion if you encapsulate the closure in a type that follows the laws of an applicative functor

Closure vs. Procedure

At the end of the day you're basically right; a continuation is a "procedure", though I would rather refer to it as a closure. Often times continuations are best expressed as first class closures that have enclosed a bound environment. In a pure functional language you might say this is not particularly reasonable because you lack references; this is true but you can enclose values and single assignment makes enclosing the value vs. the reference the exact same thing. This gives rise to in Haskell:

(\x -> \y -> insideYIcanAccess x (and y))

A language that lacks the ability to enclose a binding environment may technically lack first class closures, but even then there is some environment (generally the global) which is available to the closure.

So I would say it's more accurate to describe a continuation as: A closure being used in a particular way.


Conclusion

To the question of "Is a continuation implementable in any way other than a procedure?" No. If you don't have first class functions you really can't have continuations as such (yes function pointers count as first class functions, so alternatively arbitrary memory access can suffice).

Now to the question of "Are there any ways to express a continuation in a more abstract way than a procedure?" Expressing it as a type gives you a much greater abstraction, allowing you to treat the continuation in very general ways such that you can interact with the continuation in many more ways than just executing it.

share|improve this answer
    
This generalizes to "A continuation can simply be anything that let's you get the result of the rest of the program". Since this normally mandates having some code (the rest of the program) most languages use functions. Theoretically you can construct a continuation out of anything. During continuation conversion in my compilers, I've used partially filled trees. –  jozefg Sep 21 '13 at 1:51
    
@jozefg partially filled trees are a proper representation of a computation as an expression, but at the end of the day the actual code being written is an expression of sorts that cannot be identifiably different from a procedure, such as I understand it. That aside, partially filled trees are the compiler representation; the developers representation is expectantly a computation expression normative with the syntax and semantics of the language, which would appear to 99% of developers as a "procedure", "function" or otherwise. You're thinking from the compiler developer's perspective heh –  Jimmy Hoffa Sep 23 '13 at 15:16

One example you might like are coroutines. For example, the Coroutines from Lua or the iterators/generators from Python or C# are similar in power to one-shot continuations (continuations that you are only allowed to call once) but the continuation is not explicitly made into a function. Instead, you have have ways to advance the coroutine to until the next "yield" statement.

For example, consider the following Python program:

def my_iterator():
   yield 1
   yield 2
   yield 3

def main():
   it = my_iterator()
   x = it.next()
   y = it.next()
   z = it.next()
   print x + y + z

Its kind of similar to the following Javascript program with explicit callbacks:

function my_iterator()
  return function(cb1){
    cb1(1, function(cb2){
      cb2(2, function(cb3){
        cb3(3, function(cb4){
          throw "stop iteration";
        });
      });
    });
  });
}

function main(){
   var getNext1 = my_iterator();
   getNext1(function(x, getNext2){
      getNext2(function(y, getNext3){
         getNext3(function(z, getNext4){
            console.log(x + y + z);
         });
      });
   });
}

The Javascript example is kind of noisy because each step needs to return the next continuation in addition to returning the yielded value (in the Python keeps track of the continuation inside the ite

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.