[Bese-devel] some documentation
Larry D'Anna
smoof-ra at elder-gods.org
Fri Jun 24 21:09:44 UTC 2005
I think it would be nice to have some documentation as to how
arnesi-style continuations differ from the ones most people
are likely to be familiar with. I wrote up an explanation.
I think it's correct. If it is then it'd be nice to put it
in the docs directory for people to read.
--larry
-------------- next part --------------
(in-package #:it.bese.arnesi)
;; I'll explain this below
(eval-when (:compile-toplevel :load-toplevel :execute)
(setq *call/cc-returns* t))
;; Arnesi continuations are not quite identical to scheme
;; continuations. Since only part of the program is translated into
;; cps it is not really possible for a continuation to represent the
;; entire future of the computation. Instead it represents the future
;; of the computation, up to the point that we most recently entered
;; cps-transformed code. (or called a continuation from inside cps
;; code) Therefore the result of calling a continuation (or entering
;; cps-transformed code via with-call/cc or by calling a cps style
;; function or method) is not to abort our current computation and
;; switch to a different one like it is in scheme, but to initiate a
;; cps computation and return it's result to our current one. thus
;; the following snippet will print (foo bar) as well as (foo baz)
;; whereas in scheme it would only print (foo bar) because in arnesi
;; the call to the continuation returns, whereas in scheme it never
;; does.
(with-call/cc
(print (list 'foo
(let/cc k
(k 'bar)
'baz))))
;; Also note that the entire form returns (foo baz) and the
;; discarded return value of (k 'bar) is (foo bar).
;; Now to explain the stuff at the top: In scheme if you run (call/cc
;; x) and x returns a value then (call/cc x) simply returns that same
;; value. This is not the default behavior or arnesi, although
;; setting *call/cc-returns* to t will provide it. The default
;; behavior is abort to the most recent "cps entry-point" and return
;; the value from there. This is useful for implementing coroutines
;; because if calling a continuation doesn't abort a computation then
;; you pretty much have no other way of doing so. With
;; *call/cc-returns* set to nil the above computation will only print
;; out (foo bar) and it will return baz
(eval-when (:compile-toplevel :load-toplevel :execute)
(setq *call/cc-returns* nil))
(with-call/cc
(print (list 'foo
(let/cc k
(k 'bar)
'baz))))
;; Here is an example of how to use this construct to implement coroutines
;; It should print out the first 10 pyramid numbers.
(defmacro coro (&body body)
(with-unique-names (coro)
`(let (,coro)
(with-call/cc
(flet ((yield (x)
(let/cc k
(setq ,coro k)
x)))
(yield :ok)
, at body))
#'(lambda (x) (funcall ,coro x)))))
(let* ((tri-cr (coro (loop with num = 0
for i = 1 then (1+ i)
do (yield (incf num i)))))
(pyr-cr (coro (loop with num = 0
do (yield (incf num (funcall tri-cr nil)))))))
(loop for i from 1 to 10
collect (funcall pyr-cr nil)))
More information about the bese-devel
mailing list