[plt-scheme] another game: pacman
Hi Jon,
Jon Rafkind wrote:
> That sounds interesting and I think I understand it but can you provide
> a small example so I can analyze it more deeply?
I'm not sure where I'm mixing CSP and occam, but here's a few CSPish
primitives knocked together, and a trivial producer-consumer example.
Cheers,
Matt
;; MzScheme has omnidirectional channels. Although
;; not strictly necessary, I'm going to make the channels
;; unidirectional. This way, I can't accidentally send
;; data in the wrong direction in a process network.
(define-struct ch! (e))
(define-struct ch? (e))
;; make-csp-channel : void -> (values ch? ch!)
;; Returns two values, the input end of a channel,
;; and the output end of a channel.
(define (make-csp-channel)
(let ([channel (make-channel)])
(values (make-ch? channel)
(make-ch! channel))))
;; par : syntax
;; Allows me to easily run several expressions in
;; parallel, and the entire 'par' expression will
;; block the parent thread until all subexpressions
;; have finished executing.
(define-syntax (par stx)
(syntax-case stx ()
[(par exp exp* ...)
#`(begin
(let ([thread-descriptors
(list
#,@(map (lambda (e)
#`(thread (lambda () #,e)))
(cons #`exp
(syntax->list #`(exp* ...)))))])
(for-each
(lambda (thread-descriptor)
(thread-wait thread-descriptor))
thread-descriptors)))]))
;; ! : ch! any -> void
;; CSP uses the '!' to denote sending data down a channel.
;; I'll use that, too, and do some rudimentary checking to make
;; sure that I'm sending data down the channel in the
;; correct direction.
(define (! ch val)
(cond
[(not (ch!? ch)) (error '! "First argument to '!' must be a channel.")]
[(ch?? ch) (error '! "Cannot send down receiving end of channel.")]
[else
(channel-put (ch!-e ch) val)]))
;; ? : syntax
;; This is a syntax, because it mutates the variable expression.
;; Could obviously be done in some other manner.
;; The '?' operator reads data from the receiving end of a channel.
;; Again, borrowing from the CSP notation. Rudimentary error
;; checking to keep me from waiting on a channel end that
;; will never receive data.
(define-syntax (? stx)
(syntax-case stx ()
[(? ch var)
#`(cond
[(not (ch?? ch)) (error '? "First argument to '?' must be a
channel.")]
[(ch!? ch) (error '? "Cannot receive from the receiving end of
channel.")]
[else
(set! var (channel-get (ch?-e ch)))])
]))
;; A trivial example; prints some combination of A, B, and C.
(define (ex1)
(par (printf "A~n")
(printf "B~n")
(printf "C~n")))
;; Still trivial, but should spell CAB.
(define (ex2)
(par (begin (sleep 3)
(printf "A"))
(begin (sleep 5)
(printf "B"))
(begin (sleep 1)
(printf "C"))))
;; forever : syntax
;; Creates a loop that executes until broken
;; by some cataclysmic event.
(define-syntax (forever stx)
(syntax-case stx ()
[(forever body bodies ...)
#`(let loop ()
body
bodies ...
(loop))]))
;; producer-consumer : void -> ...
;; This example is still simple, but it demonstrates
;; channel communication across thread boundaries.
;; In parallel, I have two loops that don't terminate
;; save for under exceptional circumstances. In the first
;; loop, I increment 'x', and then send it down the channel.
;; Execution on this loop blocks until the corresponding read
;; operation takes place.
;;
;; In the second loop, I forever read and print the value
;; send over the channel. The loop blocks indefinitely until
;; a value is sent.
(define (producer-consumer)
(let-values ([(in? out!)
(make-csp-channel)])
(par (let ([x 0])
(forever
(set! x (add1 x))
(! out! x)))
(let ([y 0])
(forever
(? in? y)
(printf "~a~n" y)
)))
))
;; The producer-consumer example is poorly behaved.
;; Normally, you'd want some way of gracefully
;; shutting down your concurrent processes, as the current
;; example doesn't terminate when you press "Stop" in
;; the DrScheme REPL. Instead, you need to hit "Run"
;; to flush the environment. However, it gives you a
;; quick look at some CSPish primitives. Note that in CSP
;; there are rules about shared variable access across
;; processes (as in, there is none), as all sharing of data
;; is handled explicitly through channel communications.
;;
;; For more on CSP, see http://www.usingcsp.com/