SICP 読み (4)
新年を無事に迎える。昨晩は遅かったんですが、がき達が異様な早起きで仕方が無いので本読みを。(と、言いつつ着手は結局晩だったり)
問題 1.19 はスルー。別途、暇を見つつ着手はしたいです。年内中に 1.2 節が終われば、と思ってたなぁ、と思いつつ 1.2.5 節をぱらぱらっと眺めているんですが、ここは別途に、とゆー事にしてスルーを決定。面白そうだけに違う瞬間での現実トウヒに効果的に使える (?) かな、と。
問題 1.30
1.29 はスルーで、できれば別途。ただし「積分」なナニを再度学習する必要あり。
で、実装は以下で OK のはず。
(define (sum term a next b) (define (iter a result) (if (> a b) result (iter (next a) (+ result (term a))))) (iter a 0))
これ式の書き換えは簡単にできるようになったんですが、数学なソレが (以下略
問題 1.31
ここから 1.33 まではスルーしちゃ駄目な感じ。なんとなく 1.3 節の完了で冬休みが終わればラッキーなナニと言っても過言ではないかも。
まず、a ですが、ある範囲の積を返す手続きを product が返せば良いのかな。
factorial な定義は確か以下。
(define (factorial n) (define (fact-iter product counter max-count) (if (> counter max-count) product (fact-iter (* counter product) (+ counter 1) max-count))) (fact-iter 1 1 n))
あるいは例示されている pi-sum の実装を。
(define (pi-sum max) (let f ((s 3) (e max) (result 1)) (if (> s e) (* 4 result) (f (+ 2 s) e (* result (* (/ (- s 1) s) (/ (+ s 1) s)))))))
くそ。つい癖で、ですね。factorial の定義にアワせてみます。(result の初期値が 1 って微妙??)
(define (pi-sum max) (define (iter s e result) (if (> s e) (* 4 result) (iter (+ 2 s) e (* result (* (/ (- s 1) s) (/ (+ s 1) s)))))) (iter 3 max 1))
共通したナニを整理してみれば良いのかな。
- ui な引数は一個で処理終了な目印を指定
- 内部定義なメソドの引数は三つでこれも意味的に同様
- sum な例では初期値と最終値は引数指定しているな
- 終了判定した時に返却するナニが微妙に違うが、意味的には一緒と考えて OK
- カウンタ増分と処理結果へ積算する値の計算方法は異っている
まず、上記を元に factorial を返す product を考えてみる。lambda を返せば良いんだよな。
(define product (lambda (n) (define (fact-iter product counter max-count) (if (> counter max-count) product (fact-iter (* counter product) (+ counter 1) max-count))) (fact-iter 1 1 n)))
こんなんでも大丈夫か (ただし引数限定
(define (product n) (lambda () (define (fact-iter product counter max-count) (if (> counter max-count) product (fact-iter (* counter product) (+ counter 1) max-count))) (fact-iter 1 1 n)))
整理したソレを元に共通化してみるか。
(define (product init term next) (lambda (max) (define (iter c result) (if (> c max) result (iter (next c) (* (term c) result)))) (iter init 1)))
動作確認を。
guile> (define factorial (product 1 (lambda (x) x) (lambda (x) (+ x 1)))) guile> (factorial 6) 720 guile>
ここまでやって分かったんですが、ちょっと何かが違うな。sum は手続きを返しているとゆーよりもテンプレート的に見える。上記の解だと max しか設定できませんが、sum の例だと初期値と最大値の指定が可能だな。修正してみる。(1 返却がなんか微妙)
(define (product term a next b) (if (> a b) 1 (* (term a) (product term (next a) next b))))
動作を。
guile> (define (factorial a b) (product (lambda (x) x) a (lambda (x) (+ x 1)) b)) guile> (factorial 1 6) 720 guile>
一応正常動作な模様。反復なソレにしておこう。
(define (product term a next b) (let f ((a a) (result 1)) (if (> a b) result (f (next a) (* result (term a))))))
これもとりあえず factorial な動作確認を。
guile> (define (factorial a b) (product (lambda (x) x) a (lambda (x) (+ x 1)) b)) guile> (factorial 1 6) 720 guile>
次は例示された pi-sum を。
(define (pi-sum a b) (product (lambda (x) (* (/ (- x 1) x) (/ (+ x 1) x))) a (lambda (x) (+ x 2)) b))
試験。
guile> (* 4 (pi-sum 3 1000)) 3.14316384241919 guile>
試験において出てくる数値が微妙で emacs の scratch で一旦入力して guile にコピペしたら上記の通り動作。何が悪いのか、と guile のコンソールを睨みたおしてたら next な引数の指定で (lambda (x) (+ x 3)) としているのを発見。いかんなぁ。
しかも a と b を分けて、と思ってたんですが夢中になって色々試している内に、反復版と再帰版を作成している。でも再帰版の試験はしてないのかな。
て、再帰版で pi-sum の動作試験したら stack-overflow って orz
ため息をつきつつ一服していて stack を突き破っている事に気がつく。
guile> (pi-sum 3 1000) ERROR: Stack overflow ABORT: (stack-overflow) guile> (pi-sum 3 100) 0.78933492230439 guile> (* 4 (pi-sum 3 100)) 3.15733968921756 guile>
一応、lambda なソレも動作確認をしておく。
(define (product term next) (lambda (init max) (define (iter c result) (if (> c max) result (iter (next c) (* (term c) result)))) (iter init 1)))
動作確認を。
guile> (define pi-sum (product (lambda (x) (* (/ (- x 1) x) (/ (+ x 1) x))) (lambda (x) (+ x 2)))) guile> (pi-sum 3 1000) 0.785790960604798 guile> (* 4 (pi-sum 3 1000)) 3.14316384241919 guile> (define factorial (product (lambda (x) x) (lambda (x) (+ x 1)))) guile> (factorial 1 6) 720 guile>
今頃気がついたのですが、どちらも手続き返してるんだな。(駄目
問題 1.32 (accumulate)
うーん。a の解。
(define (accumulate combiner null-value term a next b) (let f ((a a) (result null-value)) (if (> a b) result (f (next a) (combiner result (term a)))))) (define (factorial a b) (accumulate (lambda (x y) (* x y)) 1 (lambda (x) x) a (lambda (x) (+ x 1)) b)) (define (pi-sum a b) (accumulate (lambda (x y) (* x y)) 1 (lambda (x) (* (/ (- x 1) x) (/ (+ x 1) x))) a (lambda (x) (+ x 2)) b))
動作確認。
guile> (factorial 1 6) 720 guile> (factorial 1 3) 6 guile> (factorial 1 4) 24 guile> (factorial 1 5) 120 guile> (* 4 (pi-sum 3 1000)) 3.14316384241919 guile>
あってるのかなぁ。b も。
(define (accumulate combiner null-value term a next b) (let f ((a a)) (if (> a b) null-value (combiner (term a) (f (next a)))))) (define (factorial a b) (accumulate (lambda (x y) (* x y)) 1 (lambda (x) x) a (lambda (x) (+ x 1)) b)) (define (pi-sum a b) (accumulate (lambda (x y) (* x y)) 1 (lambda (x) (* (/ (- x 1) x) (/ (+ x 1) x))) a (lambda (x) (+ x 2)) b))
うーん ...
guile> (factorial 1 2) 2 guile> (factorial 1 3) 6 guile> (factorial 1 4) 24 guile> (factorial 1 5) 120 guile> (factorial 1 6) 720 guile> (* 4 (pi-sum 3 500)) 3.14473581546695 guile>
一応動いてます。
# ってか凄いな。
結構アセり気味で進めてるんで、明日もっかい見てみた方が良いな。確か accumulate は数え上げ、と訳していたような記憶あり。
追記
数え上げ、は enum だな。(とほほ