問題3-56〜58

問題3-56。2の倍数のストリーム、3の倍数のストリーム、5の倍数のストリームをマージして、一つのストリームに作成するためには、以下のような手続きを定義します。

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

;=>1,2,3,4,5,6,8,9,10,12,14,15,16,18,20,21,22,24,25

この問題で問われていることがこれで正しいのかどうかは疑問で、(scale-stream S 2)などをmergeすべきなのかもしれませんが、それだと返ってくる値が微妙なので(14,21,22などが返ってこない)、このような手続きを書いてみました。いずれにせよ、merge自体は上手くいっていて、なるほどなと思いました。
問題3-57。add-streamsを利用したfibs手続きの解析です。紙にaddを何度も書きながら、add-streamsが適用される様子を観察しました。0,0,1,4,7,12,20,33,54,88というように増えていき、「1 + 一回前に利用した回数 + 二回前に利用した回数 = 今回の利用回数」となるようです(ただ、指数的に大きくなっている感じではないので、何か抜けている点があるのかもしれません)。しかし、前に利用したadd-streams手続きをmemo化しておけば、新しいadd-streamsは、nが1増えるごとに1回しか登場しないため、大幅に簡略化することができるのではないでしょうか?
問題3-58。以下のような手続きを定義して、それを利用してみます。

(define (expand num den radix)
  (cons-stream
   (quotient (* num radix) den)
   (expand (remainder (* num radix) den) den radix)))

(define S1 (expand 1 7 10))
;=>1,4,2,8,5,7,1,4,2,8,5,7

(define S2 (expand 3 8 10))
;=>3,7,5,0,0,0,0,0,0,0,0,0

これが何を意味しているのか、最初は理解できませんでしたが、ここの解答例を見て腑に落ちました。numにradix(10)を掛けてdenとの商を求め、再帰手続きには、numにradix(10)を掛けてdenで割った余りを渡す、ということで単にnumをdenで割っている(radix進数で)だけだということに気づきました。