SICP 読み (133) 3.5.2 無限ストリーム

問題 3.56

問題の意味がよく分からん。こーゆー意味なんだろうか。

(define S (cons-stream 1 (merge (scale-stream S 2)
				(merge (scale-stream S 3)
				       (scale-stream S 5)))))

上記を閃いた時点では、どんな出力かがイメージできておらず、以下のような試験をでっち上げ、叱られております。

  ("merge"
   ("S"
    (assert-equal 1 (stream-ref S 0))
    (assert-equal 2 (stream-ref S 1))
    (assert-equal 3 (stream-ref S 2))
    (assert-equal 4 (stream-ref S 3))
    (assert-equal 5 (stream-ref S 4))
    (assert-equal 6 (stream-ref S 5))
    (assert-equal 8 (stream-ref S 6))
    (assert-equal 9 (stream-ref S 7))
    (assert-equal 10 (stream-ref S 8))
    (assert-equal 12 (stream-ref S 9))
    (assert-equal 14 (stream-ref S 10))
    (assert-equal 15 (stream-ref S 11))
    (assert-equal 16 (stream-ref S 12))
    (assert-equal 18 (stream-ref S 13))
    (assert-equal 20 (stream-ref S 14))
    (assert-equal 21 (stream-ref S 15))
    )
   )

上記では 14 と 21 がダウト。ここでようやく理解。2、3、5 以外の因子は持たないのか。(って問題に書いてるし)
何と言えば良いのか分かりませんがこれは凄い。以下に一式を

  • 本体 (lib/3.5.1.scm)
(define-syntax cons-stream
 (syntax-rules ()
   ((_ a b) (cons a (delay b)))))

(define-syntax delay
 (syntax-rules ()
   ((_ p) (memo-proc (lambda () p)))))

(define (force delayed-object) (delayed-object))
(define (memo-proc p)
 (let ((already-run? #f) (result #f))
   (lambda ()
     (if (not already-run?)
         (begin (set! result (p))
                (set! already-run? #t)
                result)
         result))))
(define (stream-car s) (car s))
(define (stream-cdr s) (force (cdr s)))

(define (map1 p items)
 (if (null? items)
     '()
     (cons (p (car items))
           (map1 p (cdr items)))))

(define (map2 p . l)
 (if (null? (car l))
     '()
     (cons (apply p (map1 car l))
           (apply map2 (cons p (map1 cdr l))))))

(define (stream-map proc . argstreams)
 (if (stream-null? (car argstreams))
     the-empty-stream
     (cons-stream
      (apply proc (map stream-car argstreams))
      (apply stream-map
             (cons proc (map stream-cdr argstreams))))))

(define the-empty-stream '())
(define (stream-null? s) (null? s))

(define (stream-ref s n)
 (if (= n 0)
     (stream-car s)
     (stream-ref (stream-cdr s) (- n 1))))

(define (stream-map-example proc s)
;(define (stream-map proc s)
 (if (stream-null? s)
     the-empty-stream
     (cons-stream (proc (stream-car s))
                  (stream-map-example proc (stream-cdr s)))))
;		  (stream-map proc (stream-cdr s)))))

(define (stream-for-each proc s)
 (if (stream-null? s)
     'done
     (begin (proc (stream-car s))
            (stream-for-each proc (stream-cdr s)))))

(define (display-stream s)
 (stream-for-each display-line s))
(define (display-line x)
 (display x)
 (newline))

(define (stream-enumerate-interval low high)
 (if (> low high)
     the-empty-stream
     (cons-stream
      low
      (stream-enumerate-interval (+ low 1) high))))

(define (stream-filter pred stream)
 (cond ((stream-null? stream) the-empty-stream)
       ((pred (stream-car stream))
        (cons-stream (stream-car stream)
                     (stream-filter pred
                                    (stream-cdr stream))))
       (else
        (stream-filter pred (stream-cdr stream)))))

(define ones (cons-stream 1 ones))
(define (add-streams s1 s2)
  (stream-map + s1 s2))
(define integers (cons-stream 1 (add-streams ones integers)))

(define (mul-streams s1 s2)
  (stream-map * s1 s2))
;(define factorials (cons-stream 1 (mul-streams integers factorials)))
(define factorials (cons-stream 1 (mul-streams (stream-cdr integers) factorials)))

(define (scale-stream stream factor)
  (stream-map (lambda (x) (* x factor)) stream))
(define (merge s1 s2)
  (cond ((stream-null? s1) s2)
	((stream-null? s2) s1)
	(else
	 (let ((s1car (stream-car s1))
	       (s2car (stream-car s2)))
	   (cond ((< s1car s2car)
		  (cons-stream s1car (merge (stream-cdr s1) s2)))
		 ((> s1car s2car)
		  (cons-stream s2car (merge s1 (stream-cdr s2))))
		 (else
		  (cons-stream s1car
			       (merge (stream-cdr s1)
				      (stream-cdr s2)))))))))
(define S (cons-stream 1 (merge (scale-stream S 2)
				(merge (scale-stream S 3)
				       (scale-stream S 5)))))
  • 試験 (test/test-3.5.1.scm)
#!/usr/bin/env gosh

(use test.unit)
(require "3.5.1")

(define-test-suite "3.5.1"

  ("scale-stream"
   ("double"
    (letrec ((double (cons-stream 1 (scale-stream double 2))))
      (assert-equal 1 (stream-ref double 0))
      (assert-equal 2 (stream-ref double 1))
      (assert-equal 4 (stream-ref double 2))
      (assert-equal 8 (stream-ref double 3))
      (assert-equal 16 (stream-ref double 4))
      (assert-equal 32 (stream-ref double 5))
      (assert-equal 64 (stream-ref double 6))
      (assert-equal 128 (stream-ref double 7))
      (assert-equal 256 (stream-ref double 8))
      (assert-equal 512 (stream-ref double 9))
      (assert-equal 1024 (stream-ref double 10))
      )
    )

   ("tri"
    (letrec ((tri (cons-stream 1 (scale-stream tri 3))))
      (assert-equal 1 (stream-ref tri 0))
      (assert-equal 3 (stream-ref tri 1))
      (assert-equal 9 (stream-ref tri 2))
      (assert-equal 27 (stream-ref tri 3))
      (assert-equal 81 (stream-ref tri 4))
      (assert-equal 243 (stream-ref tri 5))
      (assert-equal 729 (stream-ref tri 6))
      )
    )

   ("fif"
    (letrec ((fif (cons-stream 1 (scale-stream fif 5))))
      (assert-equal 1 (stream-ref fif 0))
      (assert-equal 5 (stream-ref fif 1))
      (assert-equal 25 (stream-ref fif 2))
      (assert-equal 125 (stream-ref fif 3))
      (assert-equal 625 (stream-ref fif 4))
      )
    )
   )

  ("merge"
   ("S"
    (assert-equal 1 (stream-ref S 0))
    (assert-equal 2 (stream-ref S 1))
    (assert-equal 3 (stream-ref S 2))
    (assert-equal 4 (stream-ref S 3))
    (assert-equal 5 (stream-ref S 4))
    (assert-equal 6 (stream-ref S 5))
    (assert-equal 8 (stream-ref S 6))
    (assert-equal 9 (stream-ref S 7))
    (assert-equal 10 (stream-ref S 8))
    (assert-equal 12 (stream-ref S 9))
;    (assert-equal 14 (stream-ref S 10))
    (assert-equal 15 (stream-ref S 10))
;    (assert-equal 15 (stream-ref S 11))
;    (assert-equal 16 (stream-ref S 12))
    (assert-equal 16 (stream-ref S 11))
;    (assert-equal 18 (stream-ref S 13))
    (assert-equal 18 (stream-ref S 12))
;    (assert-equal 20 (stream-ref S 14))
    (assert-equal 20 (stream-ref S 13))
;    (assert-equal 21 (stream-ref S 15))
    )
   )
  )

scale-stream に stream を渡してるから 6 とか 15 とかが出てくるんですか。ヤッツケてしまってますが、まだオチてはいない自分も居ます。(を