SICP 3.5.1-3.5.2

3.50

脚注12

12 Schemeが標準的に用意しているmap手続きは, ここに述べたものより一般的である.
より一般的 mapは, n引数の手続きとn個のリストをとり,
手続きをリストのすべての第一要素に作用させ,
リストのすべての第二要素に作用させ,
等々させて, 結果のリストを返す.

例えば
(map + (list 1 2 3) (list 40 50 60) (list 700 800 900))
(741 852 963)

(map (lambda (x y) (+ x (* 2 y)))
     (list 1 2 3)
     (list 4 5 6))
(9 12 15)

元々のmap

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

よって、

(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))))))

ただし、argstreamsの長さが違うとおかしくなるかも? e.g. (stream-map some-proc (1 1 1) (2 2)) だと、(2 2)の第3要素が無いのでそこでおかしくなりそう

3.51

(define x (stream-map show (stream-enumerate-interval 0 10)))
0
=> x

(stream-ref x 5)
1
2
3
4
5
=> 5
(stream-ref x 7)
6
7
=> 7

3.52

(define sum 0)
; 0

(define (accum x)
  (set! sum (+ x sum))
  sum)
; 0

(define seq (stream-map accum (stream-enumerate-interval 1 20)))
; sumは1

(define y (stream-filter even? seq))
; even になるまで巡るので、 1, 3, 6 で 6
; sumは6

(define z (stream-filter (lambda (x) (= (remainder x 5) 0)) seq))
; 5の倍数になるまで巡るので 6, 10
; sumは10

(stream-ref y 7)
; yの7番目まで巡る
; yは  6 10 28 36 66 78 120 136 190 210
; sumは120

(display-stream z)
; zを最後まで巡る
; z は 10 15 45 55 120 190 210
; sumは210
; 印字は (10 15 45 55 120 190 210)

最適化を使わない場合、毎度計算(accum)がやり直されるので、どんどんsumの値が増える

; yまでは同じ
(define z (stream-filter (lambda (x) (= (remainder x 5) 0)) seq))
; 第1要素が6になる
; 6 + 2 + 3 + 4 = 15
(stream-ref y 7)
; 15 + (4 + 5 + ... + 17) = 162
(display-stream z)
; 162 + (5 + 6 + ... + 20) = 362

3.53

(define s (cons-stream 1 (add-streams s s)))

最後に出力された要素の2倍が次の要素。

1 2 4 8 …

よって n番目の要素は 2n-1

3.54

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

3.55

(define (partial-sums S)
  (cons-stream
    (stream-car S)
    (add-stream (partial-sums S) (stream-cdr S))))

3.56

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

3.57

fibs

(define fibs
  (cons-stream 0
    (cons-stream 1
      (add-streams (stream-cdr fibs) fibs))))

1番目 0 2番目 1 3番目 2 4番目 3 … n番目 n-1

メモかを使わない場合は、毎回計算がやり直されるので 1番目 0 2番目 1 3番目 3 4番目 7 … n番目 n-1の回数 + n

3.58

(define (expand num den radix)
  (cons-stream
   (quotient (* num radix) den)
   (expand (remainder (* num radix) den) den radix)))
(expand 1 7 10)
; (quotient 10 7)
; => 1
; (expand 3 7 10)
;   (quotient 30 7)
; => 4
; (expand 2 7 10)
;   (quotient 20 7)
; => 2
; (expand 6 7 10)
;   (quotient 60 7)
; => 8
; (expand 4 7 10)
;   (quotient 40 7)
; => 5
; (expand 5 7 10)
;   (quotient 50 7)
; => 7
; (expand 1 7 10)
; 以下循環
(expand 3 8 10)
; (quotien 30 8)
; => 3
; (expand 6 8 10)
; => 7
; (expand 4 8 10)
; => 5
; (expand 0 8 10)
; => 0
; (expand 0 8 10)
; 以下ずっと0

3.59

a

ストリームのn番目の要素を 1/n すれば良いので

(define (integrate-series s)
  (stream-map / s integers))

b

正弦の微分余弦 = 余弦積分が正弦

(define sine-series
  (cons-stream 1 (integrate-series cosine-series)))

余弦微分が正弦の符号を変えたもの = 正弦の符号を変えて積分すれば余弦

(define cosine-series
  (cons-stream 0 (integrate-series (scale-stream sine-stream -1))))

循環論法みたいで気持ち悪いが、遅延評価なら交互に実行すれば、求めた精度をやがて得られる。

3.60

べき級数の積の定義 https://ja.wikipedia.org/wiki/%E5%86%AA%E7%B4%9A%E6%95%B0#.E4.B9.97.E6.B3.95.E3.81.A8.E9.99.A4.E6.B3.95

(define (mul-series s1 s2)
  (cons-stream
    (* (stream-car s1) (stream-car s2))
    (add-streams
      (scale-stream (stream-cdr s2) (stream-car s1))
      (mul-series (stream-cdr s1) s2))))

3.61

(define (invert-unit-series s)
  (let ((sr (stream-cdr s)))
    (cons-stream 1
      (stream-map -
        (mul-series sr
           (invert-unit-series sr))))))

3.62

べき級数がよく分かっていないが、 f/g は gに対する級数Xを見つけて、 f と乗算すれば得られるはず。 よって、

(define (dev-series s1 s2)
  (if (= 0 (stream-car s2))
      (error "-- zero " )
      (mul-series s1 (invert-unit-series s2))))

正接は sin/cos なので、

(define tangent-series
  (dev-series sine-series cosine-series))