You're probably familiar with the idea of "transfer of control", which - in languages like C - manifests itself in statements such as break
, continue
, return
and goto
, or - in languages that support exceptions - the try
and catch
statements.
You can imagine that break
and continue
could be implemented using goto
(i.e. for every piece of code that uses break
or continue
, you could easily write equivalent code that uses goto
with appropriately placed labels).
So for now let's focus on goto
, which - as you should know from your experience with assembly - is the most basic control transfer operation (you can imagine that it would be hard to transform return
to use goto
- but we'll get on to this).
So let's suppose that you have a program (say, in C) that looks like this:
instruction1;
instruction2;
...
instructionN;
where instructionK
could either be an assignment or a function call or the statement if (condition) goto some_label
.
You could prepend each line with a unique label for goto
:
line1: instruction1;
line2: instruction2;
...
lineN: instructionN;
In languages that support first-class continuations, there is a special function call/cc
, which works like this: suppose that instructionK
has the form
...
lineK: call/cc(function(continuation) { ... })
lineK+1: instructionK+1;
...
I have used JavaScript's notation for anonymous functions here, because C does not support anonymous functions. You can see that the function has one argument, which I have called continuation
.
The body of the function is executed immediately when call/cc
is invoked, and the value of the continuation
argument will be the address of lineK+1
(roughly speaking). Or, in other words, the current continuation in lineK
is the lineK+1
- this is how you could think about it.
However, the typical interface is that it's not just address: the continuation
argument is a procedure which, when invoked, performs a jump to the lineK+1
. This is how call/cc
allows to implement a return
statement.
So you could think of call/cc
as a kind of a goto
on steroids. The thing is, that you can not only call the continuation
argument, but you can also store it in variables or other data structures.
The most interesting use of call/cc
that I have seen is the implementation of the Amb evaluator from Dorai Sitaram's book Teach Yourself Scheme in Fixnum Days (you can compare it with the version from Structure and Interpretation of Computer Programs which doesn't use call/cc
).
I have once also implemented my own mechanism for resource management using continuations, as described here.
But other than that, first-class continuations were subject to criticism, and I wouldn't recommend using them in production code (they are very similar to the setjmp/longjmp mechanism available in C, which I would also discourage. But if you'd like to see some usage example, here's how you could use it to implement multitasking in 100 lines od code).