2009-11-05
■[SICP] 2.2.3 公認インターフェースとしての並び(後半)
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html#%_sec_2.2.3
後半は、入れ子になっているデータ構造をConventional Interfaceで扱うにはどうするか、と言うお話。
お役に立つflatmapもあるので、合わせて憶えておこう。
(define (flatmap proc seq) (accumulate append '() (map proc seq)))
問題2.40
これは簡単。直前の例題から、リストを作る部分を抜き出すだけ。
(define (unique-pairs n) (flatmap (lambda (i) (map (lambda (j) (list i j)) (enumerate-interval 1 (- i 1)))) (enumerate-interval 1 n))) (define (prime-sum-pairs n) (map make-pair-sum (filter prime-sum? (unique-pairs n))))
問題2.41
これも簡単。3重ループでデータを作ってやって、それをフィルタに噛ませれば終了。
(define (unique-three-pairs n) (flatmap (lambda (i) (flatmap (lambda (j) (map (lambda (k) (list i j k)) (enumerate-interval 1 j))) (enumerate-interval 1 i))) (enumerate-interval 1 n))) (define (is-equal-three-pairs n s) (filter (lambda (pair) (let ((sum (+ (car pair) (cadr pair) (caddr pair)))) (= sum s))) (unique-three-pairs n)))
問題2.42
エイトクイーン問題。こういうの苦手なんだけど、実は難しく考える必要ないんだなぁ、と最近実感中。
悩んだら、ここを読もう。
http://d.hatena.ne.jp/tkuro/20091019/1255912771
あとは、数学ガールの第1巻もおすすめ。
漸化式の形式にしてやって、もうすでにできているものから、もう一個積み重ねるにはどうすればいいんだ?と言う考えかたでいい。
が、この問題はそもそも全体構造が示されているので、結局、フィルターの部分を書くだけなので、マッチョな人にはつまらない問題だろうなぁ。
; Queen全体 (define (queens board-size) (define (queen-cols k) (if (= k 0) (list empty-board) (filter (lambda (positions) (safe? positions)) (flatmap (lambda (rest-of-queens) (map (lambda (new-row) (adjoin-position new-row k rest-of-queens)) (enumerate-interval 1 board-size))) (queen-cols (- k 1)))))) (queen-cols board-size)) ; 0列までいったときの扱い (define empty-board ()) ; k列目のデータを加えるメソッド (define (adjoin-position row col lst) (cons (list row col) lst)) ; 配置可能かどうかのフィルタ (define (safe? pos) (define (side-exist? row lst) (cond ((null? lst) #t) ((= row (caar lst)) #f) (else (side-exist? row (cdr lst))))) (define (diag-exist? row col lst n) (cond ((null? lst) #t) ((and (= (- row n) (caar lst)) (= (- col n) (cadar lst))) #f) ((and (= (+ row n) (caar lst)) (= (- col n) (cadar lst))) #f) (else (diag-exist? row col (cdr lst) (+ n 1))))) (let ((row (caar pos)) (col (cadar pos)) (res (cdr pos))) (and (side-exist? row res) (diag-exist? row col res 1))))
- 実行例
gosh> (queens 4) (((3 4) (1 3) (4 2) (2 1)) ((2 4) (4 3) (1 2) (3 1)))
ま、合ってるっしょ。
問題2.43
queens-colの呼び出しが内側ループか、外側ループかの違い。
内側にすることで、1..7までのqueensを計算し、次に1..6と言うようにムダな計算をしてしまう。
と言うことで、計算を回す場合にはループの内外に注意。
- 余談
最近、2重配列を回す時に、
// (1) for (x = 0; x <= x_max; x++) { for (y = 0; y <= y_max; y++) { data[x][y]; } } // (2) for (y = 0; y <= y_max; y++) { for (x = 0; x <= x_max; x++) { data[x][y]; } }
(2)はなんで遅いの?みたいな話があったが、これはメモリアーキテクチャがデータの局所性を利用してまとめてデータをフェッチするためだと思う。
この辺の感覚って、意外と知らない人が多いのかなぁ、と思いました。
ちなみに、添字でi, jって言うの同種な文字なので、見間違いやすいよね〜。この辺も教科書のレベルから変えてほしいのだが。
- 6 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rlz=1T4GGLL_jaJP333JP334&q=ruby+ブロック f
- 4 http://r.hatena.ne.jp/ixixixi/知人/
- 4 http://reader.livedoor.com/reader/
- 4 http://twitter.com/mizutomo
- 3 http://atnd.org/events/1845
- 3 http://d.hatena.ne.jp/tkuro/
- 3 http://www.google.co.jp/search?q=rsync+使い方&lr=lang_ja&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja:official&client=firefox-a
- 3 http://www.google.com/search?hl=ja&client=firefox-a&rls=com.ubuntu:ja:official&hs=E5B&q=gcc+g+++??????&revid=1230458180&ei=VQD3SsywJqLk6gOgv-AV&sa=X&oi=revisions_inline&resnum=0&ct=top-revision&cd=4&ved=0CAsQ4QIoAw
- 2 http://k.hatena.ne.jp/keywordblog/plop
- 2 http://practical-scheme.net/wiliki/rssmix.cgi
