無限オブ無限

Schemeコルーチンでやってみました。

(use util.queue)
(use util.stream)
;; coroutine 
(define process-queue (make-queue))
(define (coroutine thunk)
  (enqueue! process-queue thunk))
(define (start)
  ((dequeue! process-queue)))  
(define (pause)
  (call/cc
   (lambda (k)
     (coroutine (lambda () (k #f)))
     (start))))
;;----- 

(define (gen s)
  (lambda ()
    (let loop ((s s))
      (unless (stream-null? s)
	(display (stream-car s))
	(display " ")
	(pause)
	(loop (stream-cdr s))))))

(define (manager n ss)
  (lambda ()
    (let loop ((i 0)
	       (ss ss))
      (unless (stream-null? ss)
	(when (< i n)
	  (coroutine (gen (stream-car ss)))
	  (pause)
	  (loop (+ i 1) (stream-cdr ss)))))))

(coroutine (manager 10 (stream-map (lambda (x)
				     (stream-iota -1 x 3))
				   (stream-iota -1))))
(start)

実行結果

0 3 1 6 4 2 9 7 5 3 12 10 8 6 4 15 13 11 9 7 5 18 16 14 12 10 8 6 21 19 17 15 13 11 9 7 24 22 20 18 16 14 12 10 8 27 25 23 21 19 17 15 13 11 9

改行いれて見やすくすると

0
3 1
6 4 2
9 7 5 3
12 10 8 6 4
15 13 11 9 7 5
18 16 14 12 10 8 6
21 19 17 15 13 11 9 7
24 22 20 18 16 14 12 10 8
27 25 23 21 19 17 15 13 11 9

何をやってるかというと、

  1. 無限ストリームの無限ストリーム ((0 3 6 ...) (1 4 7 ...) (2 5 8 ...) ...) をmanagerに渡す(managerは全体を統括する軽量スレッド)
  2. まずはmanagerが起動。"(0 3 6 ...) をひとつずつプリントする軽量スレッド"をフォークする。
  3. "(0 3 6 ...) をひとつずつプリントする軽量スレッド"の順番。0をプリント。
  4. キューが一巡してmanagerが起動。"(1 4 7 ...) をひとつずつプリントする軽量スレッド"をフォークする。
  5. "(0 3 6 ...) をひとつずつプリントする軽量スレッド"の順番。3をプリント。
  6. "(1 4 7 ...) をひとつずつプリントする軽量スレッド"の順番。1をプリント。
  7. キューが一巡してmanagerが起動。"(2 5 8 ...) をひとつずつプリントする軽量スレッド"をフォークする。
  8. "(0 3 6 ...) をひとつずつプリントする軽量スレッド"の順番。6をプリント。
  9. "(1 4 7 ...) をひとつずつプリントする軽量スレッド"の順番。4をプリント。
  10. "(2 5 8 ...) をひとつずつプリントする軽量スレッド"の順番。2をプリント。
  11. ... managerのカウンターで終わる。

ナナメに列挙することになります。