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