summaryrefslogtreecommitdiff
path: root/doc/ref/scheme-control.texi
diff options
context:
space:
mode:
Diffstat (limited to 'doc/ref/scheme-control.texi')
-rw-r--r--doc/ref/scheme-control.texi177
1 files changed, 134 insertions, 43 deletions
diff --git a/doc/ref/scheme-control.texi b/doc/ref/scheme-control.texi
index 8c5782a4b..38da00412 100644
--- a/doc/ref/scheme-control.texi
+++ b/doc/ref/scheme-control.texi
@@ -249,57 +249,148 @@ times.
@node Continuations
@section Continuations
+@cindex continuations
-@cindex call/cc
-@cindex call-with-current-continuation
-The ability to explicitly capture continuations using
-@code{call-with-current-continuation} (also often called @code{call/cc}
-for short), and to invoke such continuations later any number of times,
-and from any other point in a program, provides maybe the most powerful
-control structure known. All other control structures, such as loops
-and coroutines, can be emulated using continuations.
-
-@c NJFIXME - need a little something here about what continuations are
-@c and what they do for you.
-
-The implementation of continuations in Guile is not as efficient as one
-might hope, because it is constrained by the fact that Guile is designed
-to cooperate with programs written in other languages, such as C, which
-do not know about continuations. So continuations should be used when
-there is no other simple way of achieving the desired behaviour, or
-where the advantages of the elegant continuation mechanism outweigh the
-need for optimum performance. If you find yourself using @code{call/cc}
-for escape procedures and your program is running too slow, you might
-want to use exceptions (@pxref{Exceptions}) instead.
+A ``continuation'' is the code that will execute when a given function
+or expression returns. For example, consider
+
+@example
+(define (foo)
+ (display "hello\n")
+ (display (bar)) (newline)
+ (exit))
+@end example
+
+The continuation from the call to @code{bar} comprises a
+@code{display} of the value returned, a @code{newline} and an
+@code{exit}. This can be expressed as a function of one argument.
+
+@example
+(lambda (r)
+ (display r) (newline)
+ (exit))
+@end example
+
+In Scheme, continuations are represented as special procedures just
+like this. The special property is that when a continuation is called
+it abandons the current program location and jumps directly to that
+represented by the continuation.
+
+A continuation is like a dynamic label, capturing at run-time a point
+in program execution, including all the nested calls that have lead to
+it, or rather the code that will execute when those calls return.
+
+Continuations are created with the following functions.
-@rnindex call-with-current-continuation
@deffn {Scheme Procedure} call-with-current-continuation proc
-Capture the current continuation and call @var{proc} with the captured
-continuation as the single argument. This continuation can then be
-called with arbitrarily many arguments. Such a call will work like a
-goto to the invocation location of
-@code{call-with-current-continuation}, passing the arguments in a way
-that they are returned by the call to
-@code{call-with-current-continuation}. Since it is legal to store the
-captured continuation in a variable or to pass it to other procedures,
-it is possible that a procedure returns more than once, even if it is
-called only one time. This can be confusing at times.
+@deffnx {Scheme Procedure} call/cc proc
+@rnindex call-with-current-continuation
+Capture the current continuation and call @code{(@var{proc}
+@var{cont})} with it. The return value is the value returned by
+@var{proc}, or when @code{(@var{cont} @var{value})} is later invoked,
+the return is the @var{value} passed.
+
+Normally @var{cont} should be called with one argument, but when the
+location resumed is expecting multiple values (@pxref{Multiple
+Values}) then they should be passed as multiple arguments, for
+instance @code{(@var{cont} @var{x} @var{y} @var{z})}.
+
+@var{cont} may only be used from the dynamic root in which it was
+created (@pxref{Dynamic Roots}), and in a multi-threaded program only
+from the thread in which it was created, since each thread is a
+separate dynamic root.
+
+The call to @var{proc} is not part of the continuation captured, it
+runs only when the continuation is created. Often a program will want
+to store @var{cont} somewhere for later use, this can be done in
+@var{proc}.
+
+The @code{call} in the name @code{call-with-current-continuation}
+refers to the way a call to @var{proc} gives the newly created
+continuation. It's not related to the way a call is used later to
+invoke that continuation.
+
+@code{call/cc} is an alias for @code{call-with-current-continuation}.
+This is in common use since the latter is rather long.
@end deffn
-@c FIXME::martin: Better example needed.
-@lisp
+@deftypefn {C Function} SCM scm_make_continuation (int *first)
+Capture the current continuation as described above. The return value
+is the new continuation, and @var{*first} is set to 1.
+
+When the continuation is invoked, @code{scm_make_continuation} will
+return again, this time returning the value (or set of multiple
+values) passed in that invocation, and with @var{*first} set to 0.
+@end deftypefn
+
+@sp 1
+@noindent
+Here is a simple example,
+
+@example
(define kont #f)
-(call-with-current-continuation
- (lambda (k)
- (set! kont k)
- 1))
-@result{}
-1
+(format #t "the return is ~a\n"
+ (call/cc (lambda (k)
+ (set! kont k)
+ 1)))
+@result{} the return is 1
(kont 2)
-@result{}
-2
-@end lisp
+@result{} the return is 2
+@end example
+
+@code{call/cc} captures a continuation in which the value returned is
+going to be displayed by @code{format}. The @code{lambda} stores this
+in @code{kont} and gives an initial return @code{1} which is
+displayed. The later invocation of @code{kont} resumes the captured
+point, but this time returning @code{2}, which is displayed.
+
+When Guile is run interactively, a call to @code{format} like this has
+an implicit return back to the read-eval-print loop. @code{call/cc}
+captures that like any other return, which is why interactively
+@code{kont} will come back to read more input.
+
+@sp 1
+C programmers may note that @code{call/cc} is like @code{setjmp} in
+the way it records at runtime a point in program execution. A call to
+a continuation is like a @code{longjmp} in that it abandons the
+present location and goes to the recorded one. Like @code{longjmp},
+the value passed to the continuation is the value returned by
+@code{call/cc} on resuming there. However @code{longjmp} can only go
+up the program stack, but the continuation mechanism can go anywhere.
+
+When a continuation is invoked, @code{call/cc} and subsequent code
+effectively ``returns'' a second time. It can be confusing to imagine
+a function returning more times than it was called. It may help
+instead to think of it being stealthily re-entered and then program
+flow going on as normal.
+
+@code{dynamic-wind} (@pxref{Dynamic Wind}) can be used to ensure setup
+and cleanup code is run when a program locus is resumed or abandoned
+through the continuation mechanism. For instance locking and
+unlocking database records in use, or similar.
+
+@sp 1
+Continuations are a powerful mechanism, and can be used to implement
+almost any sort of control structure, such as loops, coroutines, or
+exception handlers.
+
+However the implementation of continuations in Guile is not as
+efficient as one might hope, because Guile is designed to cooperate
+with programs written in other languages, such as C, which do not know
+about continuations. Basically continuations are captured by a block
+copy of the stack, and resumed by copying back.
+
+For this reason, generally continuations should be used only when
+there is no other simple way to achieve the desired result, or when
+the elegance of the continuation mechanism outweighs the need for
+performance.
+
+Escapes upwards from loops or nested functions are generally best
+handled with exceptions (@pxref{Exceptions}). Coroutines can be
+efficiently implemented with cooperating threads (a thread holds a
+full program stack but doesn't copy it around the way continuations
+do).
@node Multiple Values