From: Matthew D Swank
Subject: CSP in common lisp
Date: 
Message-ID: <pan.2006.06.29.06.10.33.309414@c.net>
Roger Peppe, long time Inferno hacker, has released a Common Lisp version
of CSP: Communicating Sequential Processes (a la Plan 9). The Cliki page
is here http://www.cliki.net/csp.  As a long time Plan 9 fan, I was
excited to see it, and thought I would post a couple of examples.

CSP synchronizes on channel communication.  In the following examples:

? is the receive operator,
! is the send operator,
alt is the choice operator,
and spawn does about what you think it would do.

The first example is a simulation ui event handling:

;;;adapted from the squeak paper: http://research.microsoft.com/Users/luca/Papers/Squeak.pdf
(defparameter *dn* (chan))
(defparameter *up* (chan))
(defparameter *ky* (chan))
(defparameter *ms* (chan))

(defun ui-test ()
  (let ((move-to (chan))
        (typed (chan))
        (out *standard-output*))
    (labels ((mouse ()
               (? *dn*)
               (let ((p (? *ms*)))
                 (format out "moving-mouse to: ~s~%" p)
                 (force-output)
                 (! move-to p)
                 (? *up*)
                 (mouse)))
             (kbd (s)
               (let ((c (? *ky*)))
                 (if (eql c #\newline)
                     (progn (! typed s)
                            (kbd ""))
                     (kbd (concatenate 'string s (string c))))))
             (text (p)
               (alt ((? move-to coord) 
                     (text coord))
                    ((? typed chars)
                     (format out "~s::]~s~%" p chars)
                     (force-output)
                     (text p)))))

      (spawn (kbd ""))
      (spawn (text nil))
      (spawn (mouse)))))

(defun ui-events (position text)
  (! *dn* nil)
  (! *ms* position)
  (map nil #'(lambda (char) (! *ky* char)) text)
  (! *ky* #\newline)
  (! *up* nil))

ui-test sets up the event-handlers, and ui-events allows you to drive it:

CSP-TEST> (ui-test)
#<CSP::PROC {B3D7D11}>
CSP-TEST> (ui-events '(3 1) "hello everybody")
moving-mouse to: (3 1)
(3 1)::]"hello everybody"
NIL
CSP-TEST> (ui-events '(5 1) "hi dr. nick")
moving-mouse to: (5 1)
(5 1)::]"hi, dr nick"
NIL

The second example is the sieve of Eratosthenes done using a pipeline of
filters:
;;;sieve of Eratosthenes
(defun sieve-n (n)
  (let ((rv-chan (chan))
        (out-chan (chan)))
    (labels ((processor (p in-chan out-chan)
               (let ((n (? in-chan)))
                 (cond ((eql -1 n)
                        (! out-chan -1))
                       (t (when (not (zerop (mod n p)))
                            (! out-chan n))
                          (processor p in-chan out-chan)))))
               
             (pipeline (channel)
               (let ((prime (? channel))
                     (new-out (chan)))
                 (! rv-chan prime)
                 (when (not (eql -1 prime))
                   (spawn (processor prime channel new-out))
                   (pipeline new-out))))

             (collect-rv (current)
               (let ((n (? rv-chan)))
                 (if (eql -1 n)
                     current
                   (collect-rv (cons n current))))))

      (spawn (dotimes (x (- n 2))
               (! out-chan (+ x 2)))
             (! out-chan -1))
      (spawn (pipeline out-chan))
      (collect-rv '()))))

It effectively "lays its own track" as the primes that needed to be
filtered get bigger.

CSP-TEST> (sieve-n 50)
(47 43 41 37 31 29 23 19 17 13 11 7 5 3 2)
CSP-TEST> 

Anyway, I think it's worth a look.

Matt

-- 
"You do not really understand something unless you can
 explain it to your grandmother." — Albert Einstein.