[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