今年は喪中ということもあって静かな年末だった。っていうか、ここ数十年、年末年始は初日の出を名目にして九十九里浜で焚火に耽っていたのに、今年は中心人物の一人が結婚して実家に帰ってしまったから静かなんだ。本人は否定すると思うけど。みんな大人になるとなかなか遊んでくれなくなるわけか。
なにはともあれ、遊び相手といったら彼だ。
なんで、こんなにいい男にいい相手がいないんだろう。
文字どおり十年ぶりに野球をした。大人はたまにキャッチボールをすべきだと思った。
▼
2005/12/31
2005/12/27
体調(≒モチベーション)がようやく戻ってきた。体調(≒モチベーション)がもっとも悪影響するのは、人間のタスクスイッチだろう。少しくらい体調(≒モチベーション)が低下していても、ルーチン仕事はできますよ、でも、次々と要求とリソースが変化するような仕事の能率は極端に落ちる。
ところで、仕事で使っている簡単なテキストフィルタを Gauche で書き直し始めた(もとは、ほとんど Ruby 製)。こっちのほうが、メンテナンスのコスト(主にモチベーションの維持にかかるコスト)が低そうだから。
あと、ポートやモジュールやマクロのような、どちらかというと非SICPちっくな技術に対する練習も織り交ぜてみるのがねらい。マクロって、こんな場面でこんなふうに使うもの?
ディヴィグ本だけだと、実用する、という側面がぴんとこない。やっぱり On Lisp か。はやく本にならないかなあ。
時間ないなあ。
ところで、仕事で使っている簡単なテキストフィルタを Gauche で書き直し始めた(もとは、ほとんど Ruby 製)。こっちのほうが、メンテナンスのコスト(主にモチベーションの維持にかかるコスト)が低そうだから。
あと、ポートやモジュールやマクロのような、どちらかというと非SICPちっくな技術に対する練習も織り交ぜてみるのがねらい。マクロって、こんな場面でこんなふうに使うもの?
(define-syntax tag-case
(syntax-rules (else)
((_ e0 (else e2 e3 ...)) (begin e2 e3 ...))
((_ e0 (e1 e2 e3 ...)) (if (equal? e0 e1) (begin e2 e3 ...)))
((_ e0 (e1 e2 e3 ...) c1 c2 ...)
(if (equal? e0 e1) (begin e2 e3 ...) (tag-case e0 c1 c2 ...)))))
(define (tagged-line-filter tagged-line)
(let ((tag (car tagged-line))
(str (cadr tagged-line)))
(tag-case tag
('column (column-filter str))
('verbatim (verbatim-filter str))
('table (table-filter str))
('numbered (numbered-filter str))
('itemized (itemized-filter str))
('enumerate (enumerate-filter str))
(else (default-filter str)))))
ディヴィグ本だけだと、実用する、という側面がぴんとこない。やっぱり On Lisp か。はやく本にならないかなあ。
時間ないなあ。
2005/12/21
いまさらだけど、統計ブームだよなあ。
ところで数学には2種類あって、役に立ちやすいのと、そうじゃないの(全然役に立たないやつは、ない)。統計は、限られたデータから全体の傾向について言及するときにウソをつかないようにする方法なので、バリバリの前者である。某新聞の一面がウソをつきやすいのは、統計ではなく経験や思想でモノを言いたがるからだ。ウソをつかれて、すました顔をされるのは心外なので、統計的な常識が世間の常識になってほしい。正確に言うと、統計的な常識には数学的な裏づけがあるものだということが常識になってほしい。
でも、経験や思想で(だけで)モノを言いたがる人には、「数学的」であるということの肝は伝わらないんだよなあ。数字で世の中を説明できるなんて思い上がってんじゃねえ若造が、とでも言いたげな顔で嘲笑される。数学では数字はあつかわないんだけど、説明するのもめんどくさい。ディスコミュニケーション。
とはいえ、統計の教科書だけを読んでると、確かに数字(と数式)だけで世の中を説明しているような印象をうけがち。実際、実験とか調査でデータを集めて魔法の手順や数式に当てはめれば、はいできあがり、というスタイルの統計の入門書も少なくないと思う。どういう場合にどういう手順や数式が使えるか、という情報も、ノウハウとして必要ではあるけれど、それはあくまでも「すでに数学的な正しさを正しいと納得できる人」向けの情報だよ。そうでない人、例えば、「最初の状態と状態を更新するルールが決まってれば、永遠の向こうで状態がどうなっているか断言できる」という話を納得できない人は、たくさんいる。「天気予報なんていい加減のきわみだ」と根拠なく主張する人がいっぱいいる。ところが、今日の天気が晴れであり、この惑星で晴れの日の翌日が晴れの確率はきっかり90%、雨の日の翌日が雨の確率はきっかり50%であるとわかっているなら、明日の天気が晴れの確率はだいたい86%だと断言できるし、それは数学的に正しい。
この天気予報の例は、Wikipediaの Examples of markov chain から取ってきた(計算めんどくさかったんで)。これを信じて晴れの日の翌日に雨が降ったら、最初に仮定した90%と50%という確率については疑ってもいい。しかし、86%が導き出されるプロセスには疑うところがない。この、疑うところがない、というのがポイントで、疑うところと疑わないところを見分けるために数学を学ぶべきだといっても過言ではないと思う。つまり、本当に学ぶべきは、統計で用いられる手順や数式ではなく、そこへいたる数学的な抽象化のプロセスだと思うわけ。
にしては、確率論って統計に比べてさげすまれてない? 統計という、数学的確からしさでデータを判断する考え方に触れる前には、数学的確からしさを納得できるだけの素養が必要で、それには確率を、「事象÷母数」みたいな素朴な認識を越えて理解しておく必要があるんじゃないだろうか。
とはいえ、かくいう自分も、10年前に勉強したことなんてぽろぽろ忘れている。そこで、確率を扱う Scheme のプロシージャでも書いてみようと思い出した。
probability.scm
例えばサイコロを1個ふるという単純すぎるイベントの確率空間は、このように作る。
こんな例でも、確率変数という考え方の便利さは感じられる。出た目が偶数かどうかを考えるとしよう。目が偶数かどうかは、ω∊{1,2,3,4,5,6}上のf(ω) = 0 or 1(0: 奇数, 1: 偶数)という確率変数f(ω)として表現できる。これを、Scheme のプロシージャとしてそのまま書くと、こんな感じ(「even-pv」の pv は、probability variable の気持ち)。
サイコロをふって偶数の目が出る確率は、直感では 0.5 のはず。これは、この even-pv という確率変数から、実際に以下のように導かれる(一般に確率変数は確率分布関数(離散の場合は確率空間だと思っていい)を導く)。
平均や分散といった統計でおなじみの概念も、確率変数(確率空間)から導かれる。例えば分散はこんな感じ。
メモ
ところで数学には2種類あって、役に立ちやすいのと、そうじゃないの(全然役に立たないやつは、ない)。統計は、限られたデータから全体の傾向について言及するときにウソをつかないようにする方法なので、バリバリの前者である。某新聞の一面がウソをつきやすいのは、統計ではなく経験や思想でモノを言いたがるからだ。ウソをつかれて、すました顔をされるのは心外なので、統計的な常識が世間の常識になってほしい。正確に言うと、統計的な常識には数学的な裏づけがあるものだということが常識になってほしい。
でも、経験や思想で(だけで)モノを言いたがる人には、「数学的」であるということの肝は伝わらないんだよなあ。数字で世の中を説明できるなんて思い上がってんじゃねえ若造が、とでも言いたげな顔で嘲笑される。数学では数字はあつかわないんだけど、説明するのもめんどくさい。ディスコミュニケーション。
とはいえ、統計の教科書だけを読んでると、確かに数字(と数式)だけで世の中を説明しているような印象をうけがち。実際、実験とか調査でデータを集めて魔法の手順や数式に当てはめれば、はいできあがり、というスタイルの統計の入門書も少なくないと思う。どういう場合にどういう手順や数式が使えるか、という情報も、ノウハウとして必要ではあるけれど、それはあくまでも「すでに数学的な正しさを正しいと納得できる人」向けの情報だよ。そうでない人、例えば、「最初の状態と状態を更新するルールが決まってれば、永遠の向こうで状態がどうなっているか断言できる」という話を納得できない人は、たくさんいる。「天気予報なんていい加減のきわみだ」と根拠なく主張する人がいっぱいいる。ところが、今日の天気が晴れであり、この惑星で晴れの日の翌日が晴れの確率はきっかり90%、雨の日の翌日が雨の確率はきっかり50%であるとわかっているなら、明日の天気が晴れの確率はだいたい86%だと断言できるし、それは数学的に正しい。
この天気予報の例は、Wikipediaの Examples of markov chain から取ってきた(計算めんどくさかったんで)。これを信じて晴れの日の翌日に雨が降ったら、最初に仮定した90%と50%という確率については疑ってもいい。しかし、86%が導き出されるプロセスには疑うところがない。この、疑うところがない、というのがポイントで、疑うところと疑わないところを見分けるために数学を学ぶべきだといっても過言ではないと思う。つまり、本当に学ぶべきは、統計で用いられる手順や数式ではなく、そこへいたる数学的な抽象化のプロセスだと思うわけ。
にしては、確率論って統計に比べてさげすまれてない? 統計という、数学的確からしさでデータを判断する考え方に触れる前には、数学的確からしさを納得できるだけの素養が必要で、それには確率を、「事象÷母数」みたいな素朴な認識を越えて理解しておく必要があるんじゃないだろうか。
とはいえ、かくいう自分も、10年前に勉強したことなんてぽろぽろ忘れている。そこで、確率を扱う Scheme のプロシージャでも書いてみようと思い出した。
probability.scm
例えばサイコロを1個ふるという単純すぎるイベントの確率空間は、このように作る。
(define dice6
(make-probability-space
(list 1 2 3 4 5 6)
(lambda (w) (/ 1 6))))
dice6
=>
((1 . 0.16666666666666666) (2 . 0.16666666666666666) (3 . 0.16666666666666666)
(4 . 0.16666666666666666) (5 . 0.16666666666666666) (6 . 0.16666666666666666))
こんな例でも、確率変数という考え方の便利さは感じられる。出た目が偶数かどうかを考えるとしよう。目が偶数かどうかは、ω∊{1,2,3,4,5,6}上のf(ω) = 0 or 1(0: 奇数, 1: 偶数)という確率変数f(ω)として表現できる。これを、Scheme のプロシージャとしてそのまま書くと、こんな感じ(「even-pv」の pv は、probability variable の気持ち)。
(define (even-pv w)
(if (even? w) 1 0))
サイコロをふって偶数の目が出る確率は、直感では 0.5 のはず。これは、この even-pv という確率変数から、実際に以下のように導かれる(一般に確率変数は確率分布関数(離散の場合は確率空間だと思っていい)を導く)。
((lead-distribution even-pv) dice6)
=> ((0 . 0.5) (1 . 0.5))
平均や分散といった統計でおなじみの概念も、確率変数(確率空間)から導かれる。例えば分散はこんな感じ。
(variance dice6)
=> 2.9166666666666665
(variance ((lead-distribution even-pv) dice6))
=> 0.25
メモ
- まずは離散確率分布
- 測度とか気にしなくて済む
- 離散では確率空間≒確率分布だと思っていい
- 積分より総和のほうがプロシージャを書きやすい
- 確率変数という考え方がポイント
- 確率変数から確率分布が導かれる
- 確率変数から平均や分散が導かれる
- 確率変数は環をなす
2005/12/17
SICPの2.4項では、複素数を扱うプロシージャをもりもり作る例を説明している。複素数には、直行座標で表現する方法(実部と虚部のペア)と、極座標で表現する方法(ノルムと偏角のペア)があるけど、複素数どうしの和なら直行座標のほうが扱いやすいし、積なら極座標のほうが扱いやすい(積をとるっていうのは回転しながら延び縮みすることだから)。そんなわけで、どっちかの表現だけでなく、両方の表現で扱えるようにしたい。
このように表現の仕方が何通りかあるデータを扱うには、一般にいくつかのやり方がある。一番単純なのは、各データ表現ごとに衝突しないような名前を付けて、かたっぱしからプロシージャを定義していく方法。しかしこの方法では、あるデータがどの表現を意図しているのかをつねに人間が意識していなければならない。そこで、もうちょっと進んだ方法として、データにタグを付けることにする。こうすれば、タグに応じて異なる処理をするようにプロシージャを定義したり、都合がいいような表現に変換してから処理をするようにプロシージャを定義したりできる。
もっと上手いやり方は、2.4.3で説明している Data-Directed Programing という考え方である。これは、データ表現ごとに都合がいいように定義したプロシージャを集めて、それをテーブルとして管理するという方法である。そして、必要なプロシージャは、このテーブルから取ってきて使う。この方法が単純なタグを付ける方法に比べて優れているのは、それぞれの表現ごとにプロシージャの名前を区別しなきゃいけないとか、データの形式を統一しなければいけないといった心配なく、ざくざくとプロシージャを生み出せる点である。そのため、多人数での開発も容易になるし、そもそも不統一な形式で表現されているデータを一括して扱うこともできるようになる。
そうだったのかあ。何人かで並行して開発するとか、データ横断的な処理を定義するっていうのは、こういうことだったのかあ。面白い。面白すぎるよ、SICP。
しかし、2.4.3 だけでは、肝心のテーブルの扱い方はわからないのでした。「Section 3.3.3 でわかるだろう」って、そりゃないよ。3.3.3 まで読み進むのに何週間かかるとおもってんだ。Exercise 2.73 以降が解けないじゃん。
とりあえず "The Little Schemer" の Chapter 10 を参考に、この節でテーブルへのデータやりとりに使われている put と get というプロシージャを模倣するプロシージャを作ってみた。
naive-get-put.scm
とりあえず、とりあえず。
このように表現の仕方が何通りかあるデータを扱うには、一般にいくつかのやり方がある。一番単純なのは、各データ表現ごとに衝突しないような名前を付けて、かたっぱしからプロシージャを定義していく方法。しかしこの方法では、あるデータがどの表現を意図しているのかをつねに人間が意識していなければならない。そこで、もうちょっと進んだ方法として、データにタグを付けることにする。こうすれば、タグに応じて異なる処理をするようにプロシージャを定義したり、都合がいいような表現に変換してから処理をするようにプロシージャを定義したりできる。
もっと上手いやり方は、2.4.3で説明している Data-Directed Programing という考え方である。これは、データ表現ごとに都合がいいように定義したプロシージャを集めて、それをテーブルとして管理するという方法である。そして、必要なプロシージャは、このテーブルから取ってきて使う。この方法が単純なタグを付ける方法に比べて優れているのは、それぞれの表現ごとにプロシージャの名前を区別しなきゃいけないとか、データの形式を統一しなければいけないといった心配なく、ざくざくとプロシージャを生み出せる点である。そのため、多人数での開発も容易になるし、そもそも不統一な形式で表現されているデータを一括して扱うこともできるようになる。
そうだったのかあ。何人かで並行して開発するとか、データ横断的な処理を定義するっていうのは、こういうことだったのかあ。面白い。面白すぎるよ、SICP。
しかし、2.4.3 だけでは、肝心のテーブルの扱い方はわからないのでした。「Section 3.3.3 でわかるだろう」って、そりゃないよ。3.3.3 まで読み進むのに何週間かかるとおもってんだ。Exercise 2.73 以降が解けないじゃん。
とりあえず "The Little Schemer" の Chapter 10 を参考に、この節でテーブルへのデータやりとりに使われている put と get というプロシージャを模倣するプロシージャを作ってみた。
naive-get-put.scm
とりあえず、とりあえず。
2005/12/14
2005/12/11
気が抜けたせいか、今週は6:30くらいまで起きられない日が多かった。そこで思い切っておかいもの。
National 生体リズム 光・めざましシーリング ASSA 洋風シーリングライト LBP58530K::
http://www.amazon.co.jp/exec/obidos/ASIN/B0000C9IYJ/
これで4:00起きの生活がいっそう定着できる。
配送されるのは来週末なんだけど、ようやく我が家の全室(といっても2部屋)に照明が設置されることになる。もう入居して5年になるってのにね。再来週からは、今まで居間兼寝室だけにあった照明を別の部屋に移設し、居間兼寝室の照明として、この目覚しライトを使用することにしようと思う。
ちなみに、上記のリンク先はAmazonだけど、ヨドバシカメラのポイントのみで入手した。だから、一昨日出たボーナスでは、さらに別なものを買えるよ。
National 生体リズム 光・めざましシーリング ASSA 洋風シーリングライト LBP58530K::
http://www.amazon.co.jp/exec/obidos/ASIN/B0000C9IYJ/
これで4:00起きの生活がいっそう定着できる。
配送されるのは来週末なんだけど、ようやく我が家の全室(といっても2部屋)に照明が設置されることになる。もう入居して5年になるってのにね。再来週からは、今まで居間兼寝室だけにあった照明を別の部屋に移設し、居間兼寝室の照明として、この目覚しライトを使用することにしようと思う。
ちなみに、上記のリンク先はAmazonだけど、ヨドバシカメラのポイントのみで入手した。だから、一昨日出たボーナスでは、さらに別なものを買えるよ。
2005/12/10
今日の楽しかったこと
* 横浜トリエンナーレ2005
9月に入ってからちっとも余裕がなくて、ずっと行きそびれていた 横浜トリエンナーレ2005 。いよいよ閉幕が近くなったので、天気の良い日を見計らって出かけてきた。なにせ天気が良くないと、エントランスの紅白旗パタパタ(これもダニエル・ビュランの作品)がオモシロさ半分だから。今日は空も青かったし、風もそこそこあったので、かなり好条件だったと思う。
ダニエル・ビュラン以外に、特に個人的に楽しめた作品は次の2つ。作品名は忘れた。まあ、作品名はどうでもいいでしょ。
ほかにも面白い作品がたくさんあった。できればもう一回くらい、じっくり見に行きたかったかな。ちなみに12月18日まで。
* 横浜トリエンナーレ2005
9月に入ってからちっとも余裕がなくて、ずっと行きそびれていた 横浜トリエンナーレ2005 。いよいよ閉幕が近くなったので、天気の良い日を見計らって出かけてきた。なにせ天気が良くないと、エントランスの紅白旗パタパタ(これもダニエル・ビュランの作品)がオモシロさ半分だから。今日は空も青かったし、風もそこそこあったので、かなり好条件だったと思う。
ダニエル・ビュラン以外に、特に個人的に楽しめた作品は次の2つ。作品名は忘れた。まあ、作品名はどうでもいいでしょ。
- 暗闇で青やオレンジ色に光るブランコ
(ヴォルフガング・ヴィンター & べルトルト・ホルベルト) - 実際に乗ることができる。座るところ全体が着色した透明のアクリル(ガラス?)で滑らかに造詣されていて、視覚の上での幻惑的な雰囲気だけでなく、乗って遊んでも心地よい。この写真みたいなブランコが4台、夜の移動サーカスみたいな会場に展示されている感じ。係のお姉さんはいるけど、基本的にどう遊んでも文句は言われない(独占するなど、ほかの人の迷惑になる行為は別)。5分くらい並んだけど、ネズミーランドの666倍は面白いので、2回も遊んでしまいました。押し付けられ管理されるのではない、本当に楽しいインタラクティブな作品だった。
- 2つの倉庫を結ぶワイヤーを綱渡りする動物たち
(マーリア・ヴィルッカラ) - 基本的には、ここにある写真と同じものだったと思う。気が付かないと、気が付かない。さりげなく完成度が高いのがいい。
ほかにも面白い作品がたくさんあった。できればもう一回くらい、じっくり見に行きたかったかな。ちなみに12月18日まで。
2005/12/09
日替わりハピー
* Tさんと久しぶりにタマリンドにいって、タイカレーを食べたら、予想外にうまかった。昔みたいにご飯がぺちゃぺちゃじゃなかったのが、とくに。
* "Little Schemer" の Chapter 9 が飲み込めた。
で、"Little Schemer" の Chapter 9 は Y-combinator の話題なんだけど、「おまえら名前を付けずに再帰できるか?」という問いからスタートする説明はとても面白かった。で、Web をあちこち見てたら、Y-combinator について「名前を使わずに関数を再帰するための仕組み」だとして説明しているページがあった。そう言っちゃうのは、微妙に誤解だろ……(この本の影響じゃないと信じたい。)
僕自身の古い記憶と(いちおう数学基礎論が専門だった)、いまあちこち調べた部分をまとめると、Church って人が1階の記号論理体系におけるアルゴリズムの決定性を検証するのにλ算法ってのを発明して、それは基本的に変数の名前を置換したり関数を適用するだけで任意のアルゴリズムを定義するような仕組みなんだけど、そこで再帰的なアルゴリズムを定義するための道具として Y-combinator などの「適用しても関数を変化させない」ような関数を作ったって話(勘違いしていたら教えてください)。どうでもいいけど、そんな Y-combinator が話題として盛り上がっちゃうのは、それが Paul Graham の会社の名前であることと関係ないわけがない。
で、僕自身は、それが現実的にどんなアプリケーションで何の役にたつのかは知らない。動くコードとして見たのも、はずかしながら "Little Schemer" が初めて(基礎論の凡人はコンピュータなんて使わないんです!)。それでさらに調べてたら、Y-combinator は memoization に役立つみたいな話を発見。
Y overriding self-application :
http://okmij.org/ftp/Computation/overriding-selfapplication.html
memoization かあ。年内には SICP の Chapter 3 に入りたいなあ。
* Tさんと久しぶりにタマリンドにいって、タイカレーを食べたら、予想外にうまかった。昔みたいにご飯がぺちゃぺちゃじゃなかったのが、とくに。
* "Little Schemer" の Chapter 9 が飲み込めた。
で、"Little Schemer" の Chapter 9 は Y-combinator の話題なんだけど、「おまえら名前を付けずに再帰できるか?」という問いからスタートする説明はとても面白かった。で、Web をあちこち見てたら、Y-combinator について「名前を使わずに関数を再帰するための仕組み」だとして説明しているページがあった。そう言っちゃうのは、微妙に誤解だろ……(この本の影響じゃないと信じたい。)
僕自身の古い記憶と(いちおう数学基礎論が専門だった)、いまあちこち調べた部分をまとめると、Church って人が1階の記号論理体系におけるアルゴリズムの決定性を検証するのにλ算法ってのを発明して、それは基本的に変数の名前を置換したり関数を適用するだけで任意のアルゴリズムを定義するような仕組みなんだけど、そこで再帰的なアルゴリズムを定義するための道具として Y-combinator などの「適用しても関数を変化させない」ような関数を作ったって話(勘違いしていたら教えてください)。どうでもいいけど、そんな Y-combinator が話題として盛り上がっちゃうのは、それが Paul Graham の会社の名前であることと関係ないわけがない。
で、僕自身は、それが現実的にどんなアプリケーションで何の役にたつのかは知らない。動くコードとして見たのも、はずかしながら "Little Schemer" が初めて(基礎論の凡人はコンピュータなんて使わないんです!)。それでさらに調べてたら、Y-combinator は memoization に役立つみたいな話を発見。
Y overriding self-application :
http://okmij.org/ftp/Computation/overriding-selfapplication.html
memoization かあ。年内には SICP の Chapter 3 に入りたいなあ。
2005/12/07
数日前に読了した『ケルベロス第五の首』が重版していたらしい。草葉の陰からおめでとうございます。
訳者の柳下さんの日記(11/17に記載)
http://www.ltokyo.com/yanasita/diary/04112.html
日記を見ると、かなり重版修正が入っているもよう。そうなのかあ。いろんな意味で複雑だ(重版で修正って、読者の視点からすると複雑な心境であることを再確認)。それにしても、どこがそんなに変わったんだろう。明らかな翻訳ミスなのか、それとも表現に磨きをかけているのか。複雑な作品だけに、なんとか差分をWebに掲載してもらえるとうれしいんだけど……(それとも、すでに掲載されてる?)
訳者の柳下さんの日記(11/17に記載)
http://www.ltokyo.com/yanasita/diary/04112.html
日記を見ると、かなり重版修正が入っているもよう。そうなのかあ。いろんな意味で複雑だ(重版で修正って、読者の視点からすると複雑な心境であることを再確認)。それにしても、どこがそんなに変わったんだろう。明らかな翻訳ミスなのか、それとも表現に磨きをかけているのか。複雑な作品だけに、なんとか差分をWebに掲載してもらえるとうれしいんだけど……(それとも、すでに掲載されてる?)
2005/12/06
状況
* hisashim:On Lisp を読んでいるところ
* shikano:ANSI Common Lisp を読んでいるところ
ANSI Common Lispの100ページ(日本語訳のほう)には、mapcanの定義が載っている。
mapcan が破壊的なのは、nconc が破壊的だからだと思うんだけど、だったら nconc を append にすれば、非破壊型の mapcan ができるの?
最後のは Scheme だけど、まあ想定どおりに動く。
* hisashim:On Lisp を読んでいるところ
* shikano:ANSI Common Lisp を読んでいるところ
hisashim:mapcan おもしろいよな
shikano:破壊的ですよ
hisashim:いいんだよ、zip のフラットなのができるから
ANSI Common Lispの100ページ(日本語訳のほう)には、mapcanの定義が載っている。
(compose (curry #'apply #'nconc) #'mapcar)
mapcan が破壊的なのは、nconc が破壊的だからだと思うんだけど、だったら nconc を append にすれば、非破壊型の mapcan ができるの?
(define (my-mapcan fn . ls)
(apply append (apply map fn ls)))
最後のは Scheme だけど、まあ想定どおりに動く。
2005/12/03
さすがに毎日SICPばかりだと飽きるので、ちょっと気分転換に、ずいぶん前に挫折した問題に再挑戦してみる。問題は、8行×9列のマスに、下のようなクエスチョンマーク型の図形を9個描くというもの。
出展は、すぐ遊べるオンラインパズルというサイトで紹介されていた「九個の?」
http://www.geocities.jp/haayaa2000/puzzle/packing/nine_q.html
クエスチョンマークは90度ずつ回転して使ってもいいし、裏返しにして使ってもいい。つまり、以下の8種類の図形を、互いに重ならないように、8×9のフィールドに9個配置するパターンを探索する。
戦略としては、まず左から右に向かって各行を連結し、フィールドを 0~71 の整数からなる1次元のリストと見なす。そして、0~71 の整数を7つ組み合わせたリストとして、1つのクエスチョンマークを定義する。たとえば、上の8つうち、いちばん左のクエスチョンマークをフィールドの一番左上のマスから描き始めたパターンは、(0 1 10 18 19 27 45) と定義できる。とうぜん、あらゆる 7つの整数の組み合わせがクエスチョンマークを形作れるわけじゃないし、フィールドをはみ出すこともできないから、このフィールド上に描くことが可能なクエスチョンマーク(つまり長さ 7 のリスト)の種類は限られる。そこで、フィールド上でクエスチョンマークとして可能なリストをすべて洗い出し、そこから互いに交わらない 9 つのリストを取り出してくることができれば、問題がとけたことになる。
以前は Python でこの問題に挑戦していて、その時点で前半の「可能なクエスチョンマークをすべて洗い出す」ところまではすんなり解決していた。しかし、そのときは、その集合のなかから互いに交わらない 9 つの組み合わせを得る現実的でスマートな方法がわからなくて、挫してしまっていた。無謀にも、とりあえず9つの組み合わせをすべて求めてからfilterしようとしたりもしたんだけど、せいぜい4つの組み合わせを求めるまでが600Hz/512MのEDENマシンには限界だったようで、それ以上は仮想メモリもすべて枯渇して永遠に計算が進まず……むー(ちなみに、可能なクエスチョンマークは全部で208パターンある)。組み合わせを作り出しつつfilterするようにすれば、時間はかかってもとにかく解くことはできるだろうなあと妄想しつつ、get-combination を定義したりもしてみたんだけど。
いまになって再挑戦する気になったのは、Gaucheに combination-fo-each というプロシージャが用意されていたから。9つのクエスチョンマークの組み合わせを得つつ、それらが互いに交わらないか調べるのには、こんな get-distinct-n プロシージャを用意すればいいはず。
可能なクエスチョンマークの集合を valid-list とすれば、
あとは、計算が終わるのを気長にまちつつ、ぶログチェックでもしていればいいはず。ガーベジコレクションばんざい!
ただし、まだ計算終わってないので、結果は未確認。
##
#
##
#
#
出展は、すぐ遊べるオンラインパズルというサイトで紹介されていた「九個の?」
http://www.geocities.jp/haayaa2000/puzzle/packing/nine_q.html
クエスチョンマークは90度ずつ回転して使ってもいいし、裏返しにして使ってもいい。つまり、以下の8種類の図形を、互いに重ならないように、8×9のフィールドに9個配置するパターンを探索する。
## ## # # ### ###
# # # ## # # ## #
## ## # #
# # ## ##
# # # ## # # ## #
# # ## ## ### ###
戦略としては、まず左から右に向かって各行を連結し、フィールドを 0~71 の整数からなる1次元のリストと見なす。そして、0~71 の整数を7つ組み合わせたリストとして、1つのクエスチョンマークを定義する。たとえば、上の8つうち、いちばん左のクエスチョンマークをフィールドの一番左上のマスから描き始めたパターンは、(0 1 10 18 19 27 45) と定義できる。とうぜん、あらゆる 7つの整数の組み合わせがクエスチョンマークを形作れるわけじゃないし、フィールドをはみ出すこともできないから、このフィールド上に描くことが可能なクエスチョンマーク(つまり長さ 7 のリスト)の種類は限られる。そこで、フィールド上でクエスチョンマークとして可能なリストをすべて洗い出し、そこから互いに交わらない 9 つのリストを取り出してくることができれば、問題がとけたことになる。
以前は Python でこの問題に挑戦していて、その時点で前半の「可能なクエスチョンマークをすべて洗い出す」ところまではすんなり解決していた。しかし、そのときは、その集合のなかから互いに交わらない 9 つの組み合わせを得る現実的でスマートな方法がわからなくて、挫してしまっていた。無謀にも、とりあえず9つの組み合わせをすべて求めてからfilterしようとしたりもしたんだけど、せいぜい4つの組み合わせを求めるまでが600Hz/512MのEDENマシンには限界だったようで、それ以上は仮想メモリもすべて枯渇して永遠に計算が進まず……むー(ちなみに、可能なクエスチョンマークは全部で208パターンある)。組み合わせを作り出しつつfilterするようにすれば、時間はかかってもとにかく解くことはできるだろうなあと妄想しつつ、get-combination を定義したりもしてみたんだけど。
いまになって再挑戦する気になったのは、Gaucheに combination-fo-each というプロシージャが用意されていたから。9つのクエスチョンマークの組み合わせを得つつ、それらが互いに交わらないか調べるのには、こんな get-distinct-n プロシージャを用意すればいいはず。
(define (distinct? sets)
(= (length (apply lset-union = sets))
(* (length sets) (length (car sets)))))
(define (get-distinct-n set n)
(combinations-for-each
(lambda (s)
(if (distinct? s)
(begin (display s) (newline))))
set
n))
可能なクエスチョンマークの集合を valid-list とすれば、
(get-distict-n valid-list 9)
あとは、計算が終わるのを気長にまちつつ、ぶログチェックでもしていればいいはず。ガーベジコレクションばんざい!
ただし、まだ計算終わってないので、結果は未確認。