π計算(Scheme版)

既に誰かがやっているんだろうが、クロージャによる超軽量並行プロセスの簡単実装法で紹介されたπ計算をSchemeで実装してみた。実際にコードを書いてみることで、並行プロセスを使用したプログラミングスタイルがちょっと掴めた気がする。

(use util.queue)

(define (make-channel) (list (make-queue) (make-queue)))

(define (senders-of channel) (car channel))

(define (receivers-of channel) (cadr channel))

(define (channel-send channel . data)
  (let ((queue (receivers-of channel)))
    (if (queue-empty? queue)
	(enqueue! (senders-of channel) data)
	(apply (dequeue! queue) data))))

(define (channel-receive channel proc)
  (let ((queue (senders-of channel)))
    (if (queue-empty? queue)
	(enqueue! (receivers-of channel) proc)
	(apply proc (dequeue! queue)))))

(define (run-server server proc)
  (channel-receive server
	   (lambda (client arg)
	     (begin
	       (channel-send client (proc arg))
	       (run-server server proc)))))

(define (run-fib-server server)
  (channel-receive server
	   (lambda (client n)
	     (begin
	       (run-fib-server server)
	       (if (<= n 1)
		   (channel-send client 1)
		   (let ((c1 (make-channel))
			 (c2 (make-channel)))
		     (begin
		       (channel-send server c1 (- n 1))
		       (channel-send server c2 (- n 2))
		       (channel-receive c1
				(lambda (x)
				  (channel-receive c2
					   (lambda (y)
					     (channel-send client (+ x y)))))))))))))

(define (test-run-fib-server n)
  (let ((s (make-channel))
	(c (make-channel)))
    (begin
      (run-fib-server s)
      (channel-send s c n)
      (channel-receive c (lambda (x) (display x))))))