Created: Fri Nov 30 17:34:21 CET 2018
Last modiﬁed: Wed Dec 26 08:49:29 CET 2018
This might be useful when doing exercises of section 3.3 in TSPL3.
(define (make-queue) (cons '() '())) (define (putq! q v) (let ((end (cons v '()))) (begin (if (null? (car q)) (set-car! q end) (set-cdr! (cdr q) end)) (set-cdr! q end)))) (define (getq q) (caar q)) (define (delq! q) (begin (set-car! q (cdar q)) (and (null? (car q)) (set-cdr! q '())))) (define (emptyq? q) (null? (car q)))
(define call/cc call-with-current-continuation) (load "queue.scm") (define lwp-list (make-queue)) (define (lwp thunk) (putq! lwp-list thunk)) (define (kill-k x) #f) (define (next) (let ((p (getq lwp-list))) (delq! lwp-list) (p))) (define (start) (call/cc (lambda (k) (begin (set! kill-k k) (next))))) (define (pause) (call/cc (lambda (k) (lwp (lambda () (k #f))) (next)))) (define (quit) (if (emptyq? lwp-list) (kill-k 'ended) (next))) (lwp (lambda () (let f () (begin (pause) (display 'i-am-process-1) (newline) (kf))))) (lwp (lambda () (let f () (begin (pause) (display 'i-am-process-2) (newline) (kf))))) (start)
The process I had trouble picturing is described below.
(pause) are to be used in very
quitare to be used in lambdas stored in
startis to be used only once, after we setup the queue,
nextis an abstraction, used by
Let’s ﬁrst compare
pause. We see that both of them are calling
next at some point. (Except that
quit just kills the whole process manager
in case there is no more process to
(next) to. By stripping down this edge
quit, we get
(define quit next) as an almost valid definition.
It appears that
pause is like an improved
quit. When called, it will store
a lambda at the beginning of the queue (with a view to process it last).
next, which will call the procedure stored at the end of
start is a bit like
pause; except that the continuation we are interested
in is stored in a global variable. Also,
start is assumed to be called at the
end of our program, so calling this continuation allows to force quit the
pause inside of a process that contains a loop, we add a
continuation at the end of the queue; indeed, the same process, but starting
from right after
(next) to our second process. Again, we
(pause) and save a
continuation before we
(next). Wait, we only had two processes here! And
they’ve been removed from the queue by
delq! What is it exactly that
remains in our queue ?
Remain two continuations. We expect them to be processed in the same order they were created, because a queue is a ﬁrst-in ﬁrst-out data structure.
The ﬁrst continuation is equivalent to our ﬁrst process, starting after the pause, meaning that from now on, the process will actually do its thing, which is displaying a number before pausing and storing the same continuation in the queue.
We just got our ﬁrst process to perform its task for the ﬁrst time. We have two processes: one to resume our second process where it left, which we are about to call since we just paused and the new continuation of the ﬁrst process; which we’ll invoke on the next pause.