* doco continuations
@ 2003-07-07 22:17 Kevin Ryde
2003-07-24 0:32 ` Kevin Ryde
0 siblings, 1 reply; 2+ messages in thread
From: Kevin Ryde @ 2003-07-07 22:17 UTC (permalink / raw)
This is a proposed revision for the continuations node in the manual.
It tries to illustrate the concept, though at a reference manual
level, not in as much detail as a tutorial might.
At the end I mention threads for coroutines. Would that be the best
alternative to continuations? A thread plus a condition variable for
signalling it to wake up, or something along those lines.
Continuations
=============
A "continuation" is the code that will execute when a given function or
expression returns. For example, consider
(define (foo)
(display "hello\n")
(display (bar)) (newline)
(exit))
The continuation from the call to `bar' comprises a `display' of the
value returned, a `newline' and an `exit'. This can be expressed as a
function of one argument.
(lambda (r)
(display r) (newline)
(exit))
In Scheme, continuations are represented as special procedures just
like this. When a continuation is called it abandons the current
program location and jumps directly to that represented by the
continuation.
A continuation is a sort of 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.
- Scheme Procedure: call-with-current-continuation proc
- Scheme Procedure: call/cc proc
Capture the current continuation and call `(PROC CONT)' with it.
The return value is the value returned by PROC, or when `(CONT
VALUE)' is later invoked, the return is the VALUE passed.
Normally CONT should be called with one argument, but when the
location resumed is expecting multiple values (*note Multiple
Values::) then they should be passed as multiple arguments, for
instance `(CONT X Y Z)'.
CONT may only be used from the dynamic root in which it was
created (*note 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 PROC is not part of the continuation captured, it runs
only when the continuation is created. Often a program will want
to store CONT somewhere for later use, this can be done in PROC.
The `call' in the name `call-with-current-continuation' refers to
the way a call to PROC gives the newly created continuation. It's
not related to the fact a call is used later to invoke that
continuation.
`call/cc' is an alias for `call-with-current-continuation'. This
is in common use since the latter is rather long.
Here is a simple example,
(define kont #f)
(format #t "the return is ~a\n"
(call/cc (lambda (k)
(set! kont k)
1)))
=> the return is 1
(kont 2)
=> the return is 2
`call/cc' captures a continuation in which the value returned is
going to be displayed by `format'. The `lambda' procedure stores this
in `kont' and gives an initial return `1' which is displayed. The
later invocation of `kont' resumes the captured point, but this time
returning `2', which is displayed.
When Guile is run interactively, a call to `format' like this has an
implicit return back to the read-eval-print loop. `call/cc' captures
that like any other return, which is why interactively `kont' will come
back to read more input.
C programmers may note that `call/cc' is like `setjmp' in the way it
records at runtime a point in program execution. A call to a
continuation is like a `longjmp' in that it abandons the present
location and goes to the recorded one. Like `longjmp', the value
passed to the continuation is the value returned by `call/cc' on
resuming there. However `longjmp' can only go up the program stack,
but the continuation mechanism can go anywhere.
When a continuation is invoked, `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.
`dynamic-wind' (*note 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.
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, continuations should generally 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 (*note 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).
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: doco continuations
2003-07-07 22:17 doco continuations Kevin Ryde
@ 2003-07-24 0:32 ` Kevin Ryde
0 siblings, 0 replies; 2+ messages in thread
From: Kevin Ryde @ 2003-07-24 0:32 UTC (permalink / raw)
I made this change, plus a bit about the C function,
- C Function: SCM scm_make_continuation (int *first)
Capture the current continuation as described above. The return
value is the new continuation, and *FIRST is set to 1.
When the continuation is invoked, `scm_make_continuation' will
return again, this time returning the value (or set of multiple
values) passed in that invocation, and with *FIRST set to 0.
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2003-07-24 0:32 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-07-07 22:17 doco continuations Kevin Ryde
2003-07-24 0:32 ` Kevin Ryde
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).