exercise 3.63

こういう「説明せよ!」というタイプの問題は単純にコード書くより時間がかかる・・・orz

問題は

(define (sqrt-stream x)
  (cons-stream 1.0
               (stream-map (lambda (guess)
                             (sqrt-improve guess x))
                           (sqrt-stream x))))

(define (sqrt-stream x)
  (define guesses
    (cons-stream 1.0
                 (stream-map (lambda (guess)
                               (sqrt-improve guess x))
                             guesses)))
  guesses)

の違いを言ってみろ。ってことですな。

とりあえずimproveが何回呼ばれたかに着目してみる。
ということで、上のコードを変更して

(define count 0)
(define (sqrt-stream x)
  (cons-stream 1.0
               (stream-map (lambda (guess)
                             (set! count (+ count 1))
                             (sqrt-improve guess x))
                           (sqrt-stream x))))

(define (sqrt-stream x)
  (define guesses
    (cons-stream 1.0
                 (stream-map (lambda (guess)
                               (set! count (+ count 1))
                               (sqrt-improve guess x))
                             guesses)))
  guesses)

という代入を使った(大丈夫かな・・・)コードで試してみる。

で、結果だが。

1. メモ化あり+guessesとか使ってる奴
 →n番目を参照するのにimproveが n 回呼ばれる。
2.他の3つ。(メモ化あり+guesses使ってないのと、メモ化無しでguesses使ってるのと使ってないのと二つ)
 →n番目を参照するのにimproveが n*(n+1)/2 回呼ばれる。

というのになった。(結果コピペするべきかな・・・)
ちなみにn番目ってのは0から数えて。要するにstream-refつかってるんですな。


1はメモ化してるので当たり前。
初期値(0番)からn回更新されているので、improveもn回呼ばれてるはず。また、それ以上はメモ化のおかげで呼び出されないはず。


2は、よーするにメモ化が行われていないので、
n番目までに呼ばれるimproveの回数をS(n)とでもすれば、
S(n+1) = S(n) + n +1(ただしS(0)=0)
みたいになってるので、結局
S(n) = n*(n+1)/2
ってことでいいのかな。


ちなみにguesses使ってない方は、
cons-streamのcdrの部分で毎回新しくストリームを作っているので、メモ化ありのdelayを用いても、実質的にはメモ化が行われてない・・・。と言う感じかな


しかし、なんつーか結構理解が曖昧だな。もう少し動きをじっくりと追いかけたほうが良いのかな?