問題3-63〜65
問題3-59〜62は、数学的な要素が多分に含まれていて、今の自分には問題を解いたとしても正否を判定できないので飛ばしました。
そんなわけで、「3.5.3 ストリームパラダイムの開発」に入りました。代入を使うことなく、何らかの計算結果をstreamに追加していきつつ、それを使って繰り返しに計算していくようなプロセスが紹介されています。
問題3-63は、その一例であるsqrt-streamを解析せよという問題です。本文で定義されているように、improve結果を次々とconsしていけるような局所変数を利用することで、stream-mapが先へ進む際に、1からstreamを作る必要がありません。guessesへ直前にconsされた値を、stream-mapで次にmapするimprove手続きの引数に渡せます。(stream-cdr guesses)と(stream-cdr stream-map)が並行的に進むようなイメージです。Louisのように定義してしまうと、improve手続きに渡す値を求める時に、1からその値を計算しなければなりません。例えば、4回目のstream-cdrを行なう際には、1.0を4回improveしなければなりません。streamを作り直すイメージでしょうか。memo-procを使えば、一度行なった計算は、結果だけが返ってくるようになりますが、それでも非効率であることには変わらないようです。
問題3-64。許容誤差に収まるまでstreamを調べていく手続きを、以下のように定義しました。
(define (stream-limit stream tolerance) (if (< (abs (- (stream-car stream) (stream-car (stream-cdr stream)))) tolerance) (display-line (stream-car stream)) (stream-limit (stream-cdr stream) tolerance))) (define (sqrt x tolerance) (stream-limit (sqrt-stream x) tolerance)) (sqrt 2 0.01) ;=>1.4166666666666665 (sqrt 2 0.0000001) ;=>1.4142135623746899
問題3-65は、以下のように定義しましたが、euler-transformやタブローについては理解があいまいなので、深追いはしませんでした。
(define (ln2-summands n) (cons-stream (/ 1.0 n) (stream-map - (ln2-summands (+ n 1))))) (define ln2-stream (partial-sums (ln2-summands 1))) (stream-ref ln2-stream 3) ;=>0.5833333333333333 (stream-ref (euler-transform ln2-stream) 3) ;=>0.6924242424242424 (stream-ref (accelerated-sequence euler-transform ln2-stream) 3) ;=>0.6931488693329254