guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Web development


From: Keith Wright
Subject: Re: Web development
Date: Sat, 17 Nov 2001 17:07:39 -0500

> From: Sergey Dolin <address@hidden>

> > > I dont know how to store "pointer to current continuatin"... i know it
> > > is a shame for "real schemer", but i am as i am. 
> > This a triviality:
> >   (set! cc (call-with-current-continuation identity))

> A know this example :(
>   Let's go one step further: there is "dispatcher"-closure which
>   keeps set of "continuations". On some input it decides which of
>   continuation it should call next.

This made me think of writing a simple example of the use of
continuations for something slightly more complex than "escapes".
So, it is often said that continuations can be used to make
coroutines, but examples are not easy to find.  In fact, I remember
reading only one example in the easily available literature.
So I dug out one of the oldest books in my now large collection.
Copying answers from the book has the advantage in this case
that if you need to know more about what coroutines are than I
have explained here, you can go read it from the Big Man himself.
I hope somebody finds the following either useful or amusing.

;;; The following is a translation into Scheme of the example
;;; in section 1.4.2 of The Art of Computer Programming
;;; by Donald E. Knuth.

;;; Knuth describes the problem thus:
;;;> In order to study coroutines in action, let us consider
;;;> a ``contrived'' example.  Suppose we want to write a
;;;> program that translates one code into another.  The
;;;> input code to be translated is a sequence of
;;;> alphanumeric characters terminated by a period, e.g.
;;;> 
;;;>      A2B5E3426FG0ZYW3210PQ89R.
;;;> 
;;;> which has been punched onto cards; blank columns
;;;> appearing on these cards are to be ignored.  This input
;;;> is to be understood as follows, from left to right: If
;;;> the next character is a digit, say n, it indicates
;;;> (n+1) repetitions of the following character, whether
;;;> that character is a digit or not.  A nondigit simply
;;;> denotes itself.  The output of our program is to
;;;> consists of the sequence indicated in this manner and
;;;> separated into groups of three characters each.

;;; No doubt a general purpose coroutine implementation in
;;; Scheme would have a mechanism to create coroutines and
;;; save their continuations without hard-coding all the
;;; names, but this is meant to be a straight-forward
;;; translation of Knuth's example program.
;;; (If there can be a straight-forward implementation of
;;; a plan so devious as translation into Scheme of
;;; assembly language from a mid-sixties era machine.)
;;;
;;; When this program is run, it will read from standard
;;; input.  Send it the above example input, the result
;;; should be:
;;; 
;;;   ABB BEE EEE E44 446 66F GZY W22 220 0PQ 999 999 999 R.


(define call/cc call-with-current-continuation)

(define (start hlt)
  ;; |nextchar| - read next character skipping "blank columns".
  (define (nextchar)
    (let ((c (read-char)))
      (if (char=? c #\space) (nextchar) c)))

  ;; |inx| - a coroutine to read input, calling |out| to dispose
  ;; of characters.  Note that it loops "forever".  The variable
  ;; |inx| will be updated each time |out| is called so that it
  ;; always holds the continuation of the coroutine, that is,
  ;; the place in the code where execution should proceed after
  ;; the |out| coroutine is done.
  (define inx
    (lambda()
      (let in1 ()
        (let ((c (nextchar)))
          (if (char-numeric? c)
              (let ((r (nextchar)))
                (let out*n ((n (- (char->integer c) (char->integer #\0))))
                  (out r)
                  (if (not (zero? n))
                      (out*n (- n 1)))))
              (out c))
          (in1)))))

  ;; |move-char| - write a single character, then halt if it was a period.
  ;; Knuth has this coded in-line, because MIXAL is so much more concise
  ;; Scheme.
  (define (move-char c)
    (write-char c)
    (if (char=? c #\.)
        (begin (newline)
               (hlt))))

  ;; |outx| - write characters in groups of three, starting a new "card"
  ;; after 16 groups.  Note that this also loops "forever".
  (define outx
    (lambda()
      (let out1 ()
        (let h1 ((n 16))
          (move-char (in))
          (move-char (in))
          (move-char (in))
          (if (= n 1)
              (begin (newline) (out1))
              (begin (write-char #\space) (h1 (- n 1))) )))))

  ;; |in| - save the "return address", i.e. the place from which |in|
  ;; was called, and then call the continuation inside the input
  ;; coroutine that was saved when we last left it.
  (define (in)
    (call/cc (lambda(return)
               (set! outx return)
               (inx))))

  ;; |out| - completely symetric, except it takes a parameter.
  (define (out c)
    (call/cc (lambda(return) 
               (set! inx return)
               (outx c))))

  ;; to start the process, just call the output coroutine.
  (outx) ) ;end of (define (start hlt) ...)

;;; We now pass the current continuation (which is the end
;;; of the program) to the |start| procedure.  It refers to
;;; this continuation as |hlt|.
(call/cc start)
                         




reply via email to

[Prev in Thread] Current Thread [Next in Thread]