2006/10/27


校正待ちですることがないので(後半はうそ)、Code Golf の "Switchboard" という問題に手をつけてみた。コードを短くすることはともかく、この問題は解法を考えるのが面白かった。いまのところ23位だけど、これが個人的なスキルの限界だと思う。

Scheme は受け付けてない。そうとはしらず最初は暢気に Scheme で書いたことはいうまでもない。しょうがないので Ruby で書き直したんだけど、"gets" だけで標準入力から1行読み取れるなんて。実用的にもほどがある。

2006/10/26


おいしいとんかつの店は三河島の「山き(きは「七」を森のように重ねた字)」だよ! このへん
どうもあんまり知られてないようなので、叫んでおく。

ヒレがびっくり。とんかつといえばロースだと信じてたのに、その常識を覆された。あと、メンチ。ヒレもメンチもそれまでどっちかっていうとバカにしていた料理だったけど、本当にごめんなさい。もちろんロースもうまい。
ただ、メニューが少ないし、キャベツに対する選択肢がソースしかないので、軟弱な人にはおすすめしない。地元ゆえのひいき目っていうのもある。それでも、普通の豚を普通のとんかつとして硬派に堪能したいなら、絶対におすすめ。普通なのに、軽くびっくりするんだよね。外食にはびっくりが必要だと思う。しみじみうまいだけなら家で食うさ。

店内の色紙によると、阿佐谷の「かつ源」という店からのれんわけしたようだ。あんまり知られてなくて、いつも暇そうにしているので、ちょと応援したい。


SICP の ex. 4.11〜4.13 をうろうろしていたら、ようやく set-car! や set-cdr!が set! と根本的に違うことが飲み込めてきた。いままでそんなこともきちんと知らなかったのかよ。

たとえば次の2つの例は、いっけんすると同じ結果になる。つまり a に (0 1 2 3) が束縛された状態になる。
(define a '(1 2 3))
(let ((current-a (list-copy a)))
(set-car! a 0)
(set-cdr! a current-a))

gosh>a
(0 1 2 3)
(define a '(1 2 3))
(set! a (cons 0 a))

gosh>a
(0 1 2 3)
set-car! と set-cdr! の場合には、もともと a が指し示す領域にあったデータが書き換わっている。それに対して set! でやっていることは、もともと a が指し示す領域にあったデータは換わってなくて、a という名前で束縛されていたものを別の場所に cons して作った (0 1 2 3) に 付け換えたにすぎない。

で、この違いを理解していないことが ex. 4.11 付近で評価器が扱う環境の定義をしたりするときにネックになるわけで、define したつもりのものが環境に登録されずに悩むことになったりするのは僕だけか……。ところで「Schemeは十分に抽象的だけどビットが透けて見えることがある」みたいなことを言ったのは誰だっけ?

この話のとってつけたような結論はお好みに合わせて随時読みかえることができます。
  • やっぱりローレベルの知識が足りないやつは帰れってことだよね。そういえばJoelさんもそんなようなことを言ってたなあ。
  • やっぱり参照透過じゃないとだめだよね。びっくりマーク?なにそれ。





どうでもいいけど、僕は、こういう基本的なことを知らなかったという「恥」を恥と承知して公にさらすことには旨味があると思っている。これは、「知らないなりに考えてみたけど間違ってたら誰か教えてね」という意味ではない。なんか、そういう恥2.0みたいなノリじゃない。恥2.0ではブログツールのコメントとかトラックバックとかはてな何とかとか巨大掲示板といったAPIによりあなたの恥を知識と経験に昇華してあわよくばWebコミュニティへのネタを提供します。よかったね。あるいは、「自分は知らないことを知らないまま放置しない向上心と努力あふれる人間であります」というアピールになるという意味でもない。そういう態度がアピールにはなるのは、ぶっちゃけ小学校の教師に対してだけだろう。努力だけはしてるように見える人と、どこで勉強してるかわかんないけどアウトプットをきちんと出している人がいたら、自分は後者と仕事することを選ぶ。

「聞くは一瞬の恥」とかいうけど、僕には、それで教えてもらった内容だけを自分のなかに保存することができない。恥体験と一緒だから内容が見に付くという側面があるように思う。この側面は、自分自身に固有の経験だけから傍証しているものなので、ほかの人にも当てはまるのかどうかは知らない。まあ、恥も外聞もなく分からないことを聞きまくっている人間にろくなスキルを見に付けていない(ように見える)のが多いとは思うけど。

ようするに独学でスキルを得るには恥の追体験が必要ってことだ。将来の自分は、今日書いた内容を恥ずかしく思い返す必要がある。紙の大学ノートに同じことを書いてもいいんだけど、それは「恥」じゃないんだよね。将来の自分は、今日書いた内容を公開したことを恥ずかしく思い返す必要がある。このノートは恥のタイムシフト装置です。

2006/10/24

temp

emacs から blogger に投稿したい。

Atom Publishing Protocol というのがあって、それをemacs から使えるようにする atom-blogger.el というのがあった。設定方法はここに丁寧に解説されている。

Using atom-blogger with emacs to post to blogger
http://phototechnic.blogspot.com/2006/03/using-atom-blogger-with-emacs-to-post.html

emacs への設定だけをしても、captcha が邪魔するらしく、まったく投稿できない。captcha をオフにする方法もよくわからない。さんざんあちこちクリックして、投稿時のcaptcha の横にある「?」マークをクリックすれば captcha を解除するメニューに入れることが気づいた。なにそれ。

で、そのメニューいわく、「Bloggerのスパム対策ロボットにより、このブログにスパム ブログの疑いがあることが検出されました」。

どうやら captcha による投稿時の認証は、ユーザが望んでオンになるものではなく、bloggerの運営者が「スパムブログ」と判断したものに勝手に設定しているらしい。さっきまでこのノートは Link Spam(Wikipedia)に使われてたらしいよ。Wikipedia によると "Search engine spammers, on the other hand, are generally aware that the content that they promote is not very useful or relevant to the ordinary internet surfer."

ぐうのねもでませんって。

2006/10/23

ツインピークスで、クーパー捜査官がこうつぶやくシーンがある(wikiquote)。


Every day, once a day, give yourself a present.
Don't plan it, don't wait for it, just… let it happen.

毎日ひとつ、自分にプレゼントを。
用意したり待ち望んだりするプレゼントじゃなくって、なにげないやつでいい。


クーパーはこのセリフを、確か一杯のコーヒーについて言っていた気がする。恋人のアニーが一緒だったような気もする。いかんせんセカンドシーズンのDVDがいつまでたってもリリースされないので、そんなようなシーンを記憶の中で作り上げていただけかもしれない。どうでもいいけど、アニーとクーパーはショーペンハウアーのネタで盛り上げれるキチガイだ。

そんなわけで、コーヒーを楽しく飲むと、もう一日の楽しみが潰えたような心地になる。

2006/10/17

同じグループの同僚が鼻歌まじりで仕事してたりすると、不思議に自分も仕事に集中できるもんなんだな。集中しようという意識が持て、しかもそれに成功する。一緒に仕事している人間が上機嫌だってことは、彼女の仕事もうまく動いてるってことだ。そんなプラスの気配がいつも充満している職場ならパーティションはかえって邪魔だろう。たぶんバランスボールのある職場にいる人達はそれを知ってる。

生産性のことさらに低い同僚が鼻歌まじりだったりすればイライラが募る。だから、生産性の低い人間を雇い続けなければいけない職場ではパーティションが必要なんだろう。パーティションより必要なものがあるような気がするので、パーティションを作ってくれとはいわない。せめて本棚をください。

2006/10/10

名前付きletをlambda式にしたい。

SICPの第4章では、Schemeの式の評価機をSchemeで書く。こう書くとやたらに抽象的で深遠でカッコよさげに聞こえるけど、まずはプロシージャをいくつかのスペシャルフォームによる表現に均さないといけないからandやorをletをlambdaにするとか、そういうどちらかというとバタ臭い作業が続く。
で、ex.4.8では、名前付きletをlambda式にしろとある。letrecがないので、たぶん正解はinternal defineを使う方法。でも、そろそろ式の表現を変換するだけの作業には飽きてきたので、不必要に解答をややこしくしてみる。つまり、要するに関数を再帰させる話だと解釈して、こういう問題設定にする。

再帰的なプロシージャを抽象化したい。

答えは分かっている。Yコンビネータだ。というわけで、以下はYコンビネータのおさらい。"The Little Schemer"の第9章の翻案ともいう。

まず、再帰を含む関数を用意する。たとえばex. 4.8のフィボナッチ名前付きlet版。
(define (fib n)
(let fib-iter ((a 1) (b 0) (count n))
(if (= count 0)
b
(fib-iter (+ a b) a (- count 1)))))

count≠0 のときに再帰しているので、 count > 0 のときに適当に答えを出してくれる fib-iter-1 というプロシージャが世界のどこかでよろしく定義されていると妄想する。
(define (fib n)
((lambda (a b count)
(if (= count 0)
b
(fib-iter-1 (+ a b) a (- count 1))))
1 0 n))

再帰しないですむようになったので、もうletに名前はいらない。それで、ついでにletをlambda式にしておいた。もちろん、実際には fib-iter-1 なんていう都合のいいプロシージャはないし、もしあっても fib-iter-1 の中にはきっと再帰があるだろう。fib-iter-1 の再帰を片付けるのに fib-iter-2 を妄想し、さらに fib-iter-2 の再帰を片付けるのに fib-iter-3 を妄想し、……嘘をつき続けなければならない。

そこで発想を飛ばして、「fib-iter-1を妄想する」ことを抽象化してみよう。ちょっと分かりにくいけど、妄想したいものを受け取ってfibの中身のlambdaを返してくれるようなプロシージャを作ればいい。つまりこんな感じ。
(lambda (fib-iter)
(lambda (a b count)
(if (= count 0)
b
(fib-iter (+ a b) a (- count 1)))))

ただし現実には「妄想の果て」が必要になる。また妄想なんだけど、とりあえず果てに行き付いたので無理矢理納得することにする。妄想の果てを fib-iter-omega とすると、
(define (fib n)
(((lambda (fib-iter)
(lambda (a b count)
(if (= count 0)
b
(fib-iter (+ a b) a (- count 1)))))
fib-iter-omega)
1 0 n))


ここで再び発想を飛ばして、今度は「妄想の果て」を抽象化する。それには、妄想を受け取って妄想を返し続けるようなプロシージャを作ればいい。こんな禅問答のようなプロシージャが考えられる。
(lambda (fib-iter) (fib-iter fib-iter))

これってつまり「関数を自分にぶちこむ」ってことなので、「再帰する」ことを抽象化しているとも考えられる。

ところが、実はこれだけだと果てしなく続く妄想だけになっちゃて、妄想の仕様が何も分からない。仕様がないものは使いようがない。そこで、まずは妄想を整形してやって、それを「果てしなく続く妄想」に渡すようにしてやりたい。いま考えているfib-iterでは3つの引数(a,b,const)を使っているので、この「妄想の果て」も3つの引数をとるプロシージャを返すようにしないといけない。
(lambda (delusion)
((lambda (fib-iter) (fib-iter fib-iter))
(lambda (f) (delusion (lambda (x y z) ((f f) x y z))))))

妄想delusionを受け取って、それを3引数を取るプロシージャの形にして、後はひたすら妄想を続けるというノリ。これがYコンビネータ。だからYコンビネータは、妄想を使えるものにするための、どっちかっていうとテクニカルな細工なんだと思う。

以上をfibに取り込むと、こうなる。
(define (fib n)
(((lambda (delusion)
((lambda (fib-iter) (fib-iter fib-iter))
(lambda (f) (delusion (lambda (x y z) ((f f) x y z))))))
(lambda (fib-iter)
(lambda (a b count)
(if (= count 0)
b
(fib-iter (+ a b) a (- count 1))))))
1 0 n))


もうすっかり妄想が抽象化されつくしたので、これはフィボナッチ数列のn項を求めるプロシージャとしてちゃんと評価される。

gosh> (map fib (iota 20))
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)

2006/10/02

御徒町の工具屋さんにPBの六角レンチを1本買いにいったつもりが、お店の人にそそのかされてStahlwille(スタビレー)のコンビネーションレンチを5本買ってしまった。まともなスパナをもってなかったので、ちょうどいい機会だったと思うことにしよう。っていうかほしかったんです。

R0010351

スタビレーはドイツの老舗工具メーカーで、Snap-onみたいなテカテカのアメリカ工具がもてはやされる昨今ではむしろ珍しくなってしまった梨地仕上げの表面加工で有名(やっぱ工具はドイツだよなあ。ちなみにPBもドイツはスイスだった)。購入したのは、今年から製造中止になってしまったOpen-Box Type 15というコンビネーションレンチの10mm, 12mm, 13mm, 14mm, 17mm。

Stahlwilleのプレーンなコンビネーションレンチには、大きく分けるとType 13とType 14というのがあって、全長がちがう。Type 14のほうが長い。Type 15は、長いほうのType 14と同じ全長で、オープンエンドの形状が違う。Type 15のオープンエンドは側面が凸曲線に加工されていて、StahlwilleではSoftGRIPと呼んでいた。奥の形状も六角形のボルトヘッドに近いものになっている。写真左がType 15で、右はずいぶん昔にホームセンターで買った安物。

R0010346

一般にオープンエンドのレンチでボルトに強い力をかけると、6面あるうちの2面(もっというと、その2面の片方の対角線のエンド2点だけ)しか接触しないので、ボルトヘッドをなめやすい。そのためコンビネーションレンチは、オープンエンド側で仮締めや早回しをしてメガネ側で強い力をかけるのが正しい使い方。とはいえ、とくにアマチュアだと、オープンエンド側でもそれなりに力をいれたい場合がある。というわけで、Type 15のようなオープンエンドがうれしい。それに側面が凸になっているってことは、口が開いてるってことでもあるわけで、早回しの際にボルトヘッドにひっかけやすいのもうれしい。どこかの通販サイトによると、"The sculptured jaw provides an extra grip on screws and nuts with 25% more static load capacity and 40% more permanent load capacity than standard wrenches. "だって。(残念ながら公式の情報は見つからなかった。)

ところがType 14よりちょっぴり定価が高かったせいか、ドイツでは流行らなかったらしい(お店の人談)。まあ、ドイツの職人はアマチュアにうれしいツールをわざわざ高い値段で買わないってことなのかもしれない。そんなわけで、すでに入手できるのは現在流通しているもののみ。ただ、今のところ在庫処分扱いなので、どうやら安売りしてるっぽい。スタビレーのレンチ5本が9000円以下ってだけで、かなりお買い得。

2006/09/30

GaucheにもRubyみたいなARGFがほしい。
正確にいうと、ほしがっているのは僕じゃないんだけど、確かにARGFみたいな仕組みがあると使い捨てのテキストフィルタを書いたりするのは簡単になりそうだ。Gaucheのマニュアルではmainを使うことが推奨されているけど、気楽で泥臭いスクリプトを作りたいことだってある。

RubyのリファレンスマニュアルのARGFの項目には「スクリプトに指定した引数 (ARGV を参照) をファイル名とみなして、それらのファイルを連結した 1 つの仮想ファイルを表すオブジェクト」とある。その説明がARGFのすべてなら、Gaucheに用意されている仮想ポートで似たようなものが作れるかもしれない。

でっちあげてみた。引数として渡されたファイルのテキストをいったんバッファに吐き出しているので、Rubyのように*argv*のリストが変更されるわけではない。バッファが空なら標準入力を読む。
#! /usr/local/bin/gosh

(use gauche.vport)
(use srfi-13)

(define argv-str
(let R ((files *argv*) (str ""))
(if (null? files)
""
(call-with-input-file (car files)
(lambda (port)
(let ((joined-string
(string-join (list str (port->string port)) "" 'strict-infix)))
(if (not (null? (cdr files)))
(R (cdr files) joined-string)
joined-string)))))))

(define (getc str)
(cond ((> (string-length str) 0)
(let ((c (string-ref str 0)))
(set! argv-str (string-drop str 1))
c))
((= (string-length str) 0)
"")
(else
(error "Out of Range -- getc"))))

(define (argf thunk)
(if (string-null? argv-str)
(with-input-from-port (current-input-port)
thunk)
(with-input-from-port
(make <virtual-input-port>
:getc (lambda () (getc argv-str)))
thunk)))

;;; test
(argf (lambda ()
(port-for-each
(lambda (line) (print (regexp-replace #/hello/ line "damn")))
read-line)))


実行結果
$ cat test.txt
hello world
this is argf test
$ ./argf.scm test.txt test.txt
damn world
this is argf test
damn world
this is argf test
$ cat test.txt test.txt | ./argf.scm
damn world
this is argf test
damn world
this is argf test

作ってから必ず思う、すでにこんなのは誰かが作っているんではないだろうか。

2006/09/26

荒れまくっていたウィキペディアの実数の項目が素敵な解説に直されて先週復活していた。編集履歴を見ると、Makotoyさんという方の尽力らしい。

荒れる原因になったもとの解説は数直線を使ったもので、「実数は有理数を項とする無限数列の収束値として得られる」と説明していたようだ。で、そこからなぜか無限小数の表現が0をのぞいて一意に決まるとか決まらないとかの議論になって、それで紛糾していたらしい。なにか世界には「実数」という確固たるモノがあるって素朴に思いがちだけど、実際には順序と演算を適切に用意してやることで公理的に決まるだけのものにすぎない。つまり、数字を使わなくても構築できて、でもそれは結局は数字で表現するふつうの実数と同型になる。そんなわけで、数字とか数直線上の点をもって実数とは何かを議論するのは、あんまり意味がないと思うんだけど、どうして1.0000……とか0.9999……とか、数字に異常に固執する人がいるんだろう。きっとあれだ。小学校の教師が悪いんだ。

2006/09/21

行列の固有値を求めたい。
なにをいまさら感たっぷりなんだけど、理系の出版社でテクニカルレビューっぽいことをしていると、特に統計の本なんかで行列の固有値を検算したい場合がなきにしもあらず。たいていは Maxima に突っ込んじゃえばいいんだけど、Maxima では特性多項式を作ってそれを解いているらしく、うまく解が求まりやがらないことがある。実際、maxima/share/matrix/eigen.macを見ると、charpolyという関数で特定多項式を作り、それをsolveという関数で解いている。で、この solve という多項式を解く関数がうまくないといったことがMaximaのマニュアルにも書いてある。
eigenvalues calls the function solve to find the roots of the characteristic polynomial of the matrix. Sometimes solve may not be able to find the roots of the polynomial
幸い、固有値を求めたい行列は対称行列ばっかりなので、自分でJacobi法をナイーブに実装してみた。対称行列だとうれしい理由やJacobi法については『プログラミングのための線形代数』の第5章で。

jacobi.scm
gosh> 
(define A
((make-matrix 6 6)
0.68 0.65 0.8 0.11 0.01 0.14 0.65 0.88 0.89 0.02 0.19 0.01 0.8 0.89 0.91 0.02 0.04 0.1 0.11
0.02 0.02 0.81 0.82 0.77 0.01 0.19 0.04 0.82 0.81 0.64 0.14 0.01 0.1 0.77 0.64 0.66))

gosh> A
((0.68 0.65 0.8 0.11 0.01 0.14) (0.65 0.88 0.89 0.02 0.19 0.01) (0.8 0.89 0.91 0.02 0.04 0.1)
(0.11 0.02 0.02 0.81 0.82 0.77) (0.01 0.19 0.04 0.82 0.81 0.64) (0.14 0.01 0.1 0.77 0.64 0.66))

gosh> (eigenvalues-jacobi A)
(-0.010575430595377565 -0.09400171282374802 2.109504119397093 -0.08138275206455295 0.279213041557744 2.5472427345288424)


行列のデータをどういうふうに表現すべきなのか、ひどく悩んだ。Dybvig 本のようにベクトルを使うのがセオリーなんだろう。ベクトルなら行列のij要素を取り出したり変更したりするのも簡単だ。でも、行と列を順繰りになめて各要素をちこちこ掛けたり足したりする処理ばっかり書くことになりそうで、ちょとブルー。そんなわけで今回はあえてリストのリストとして定義した(行ベクトルが1つのリスト。それを要素に持つ縦ベクトルのリストが行列)。リストなので、行列の積や和なんかも高階関数だけで定義できる。
(define (matrix-transform m)
(apply zip m))
(define (matrix-product m1 m2)
(if (not (= (line-length m1) (row-length m2)))
(error "Matrix-Product Not Defined" (list m1 m2))
(apply (make-matrix (line-length m1) (row-length m2))
(map (cut fold + 0 <>)
(map (cut apply map * <>)
(cartesian-product (list m1 (matrix-transform m2))))))))
(define (matrix-sum m1 . ms)
(map (cut apply map + <>)
(apply zip m1 ms)))
ちょっと満足。ただし単位行列や回転行列を定義するのに要素を頭からなめるはめになってるんだけどね。満足しちゃだめ!

2006/09/18

ときどきむしょうにハンダ付けがしたくなる。ちょうど先週、妙に面白いキットばかり開発して秋月で販売しているトライステートからSHOUTcast形式のインターネットラジオを再生するBBシャウトというキットが発売されたので、これを作ってみた。お値段はちょっぴり張りますが。

SHOUTcastはWinAmpで有名なNullsoftが開発したストリーミング技術で、MP3などのメディアをHTTPの拡張を使ってサーバからマルチキャストするものらしい。受信と再生はWinAmpだけでなくiTunesなどでもできる。ただ、どうやら日本にはあまりサーバがない。現に、Wikipediaには「ストリームの生成にはSHOUTcastのサービスを使うのが現実的な選択」とあるのに、ウィキペディアを見ると「インターネット放送の集合体」という適当な扱いを強いられている。まあ、ジャズとクラシックを無作為に流しっぱなしにするだけなら困ることはない。ところで店舗でBGMに海外のSHOUTcastを流してても、やっぱりJASRACから破廉恥な請求を受ける危険があるのかしら。

で、このSHOUTcast形式で配信されているストリームを受信して再生する専用のボードがBBシャウト。キットは、僕のような素人でも2時間くらいで完成します。いわゆるブロードバンドルータにつないで電源とスピーカーを接続すれば、プリセットされている放送局の音源はすぐに聴ける。

bbshout-env

やっぱり箱に入れないと不便だな。

2006/09/14

個人的な理由で2日間会社を休んでいる間に Debian サーバがアップデートされていた。ありがとうございます && ごくろうさまです > hさん。ところでなんか amazon から不思議な商品が届いたんですが、これを何に使えと?

で、アップデートの結果、telnet でログインできなくなっていた。まあ、telnetd を動かさないこと自体はまったくOKっす。ただ、今まで TeraTerm から SSH2 でログインする気になれなかったので、サーバ上には公開鍵がないんです。公開鍵を登録しようにもサーバにログインできないんです。
幸い samba が利用できるようだったので、エクスプローラ上で公開鍵をコピーして ~/.ssh/authorized_keys を作った。これでつながるよね。
ところが TeraTerm(SSH2,utf-8対応版)でまったくつながらない。Cygwin からもだめ。TeraTerm のダイアログに表示されるエラーメッセージは意味不明だし、Cygwin から ssh コマンドで接続を試みても "Permission denied (publickey)."といわれるばかりだし。

結局『OpenSSHセキュリティ管理ガイド』の267ページを見てようやく解決した。~/ssh/authorized_keys のパーミッションが user 以外に書き込み可能になってたりすると、この "Permission denied (publickey)." というエラーが出るらしい(ただし、StrictModes が no ならエラーにならない)。今回のケースだと samba から authorized_keys を作ったので、そのパーミッションは 666 になっていた。しょうがないので、あきらめてコンソールからログインしてパーミッションを設定しなおす。

教訓

* 最初からコンソールに移動して作業しろ
* エラーメッセージは google する前に本で調べろ

2006/09/12

会社を休んで日本ソフトウエア科学会のPPLサマースクールを受講してきた。へとへとになって日暮里まで帰ってきて、考え事をしながら歩いてたら、道に迷った。もう天才的な方向音痴のCさんを馬鹿にできない。っていうか、最近Cさんにセクハラで訴えられかねないくらいつらくあたりすぎ。本当に反省しています。ごめんなさい。

第4回プログラミングおよびプログラミング言語サマースクール
http://www.math.nagoya-u.ac.jp/~garrigue/ppl_ss06/


圏論の諸相(講師:木下佳樹先生)

冒頭で「諸相といっても2時間で話せるのはせいぜい1相」という前フリがあったけど、本当にそうだった。そんなわけで、Haskell→圏論というノリの参加者にはつまらなかったかもしれない。
個人的には、これまで聞きかじっている知識に横糸を何本か通すことができてよかった。以下、講義中に勝手に頭の中で構成したまとめ。絶対に参考にしてほしくないわけですが(どうせこんなページに圏論について真剣に知りたい人はこない)、詳しい人に勘違いを指摘していただくのは大歓迎です。

圏論ってのは、「集合全体の集合」とか「写像全体の写像」のように、集合論だけだとパラドクスを誘発しかねない何かを扱うべく捻り出された概念なんだよね。たしか。だから、「集合全体の集合」みたいなものにやばさを感じない限り、そもそも圏論のありがたみとか面白さはわからないような気がする。講義で「"small"な集合」という言い方を強調してたり、「集合の要素を使わずに単射の定義を与えてみよう」というクイズで「集合全体の集合を認める」という但し書きをしていたのには、そういう事情があるはず。
で、この「集合の要素を使わずに単射の定義を与えてみよう」クイズがえらく自分のツボに入った。集合AからBへの単射っていうのは、ぶっちゃけると集合Aの要素と集合Bの要素が1対1に対応しますってことで、それを「要素」とか言わないで定義しろっていうのがクイズの趣旨。答えはこうなる。
f が集合 A から集合 B への単射
=def
任意の集合C と任意の h,k:C→A について f・h = f・k ⇒ h = k
つまり、単射という写す集合と写される集合の要素に関する問題を、移すほうに値域を持つ別な任意の写像(ただし定義域は固定)どおしの関係として定義すればいいってこと(ちなみに講義では、たぶんあえて、定義域とか値域うんぬんの議論をぼかしてた。当たり前っちゃ当たり前のことなんだけど、これが固定されていないと f との合成写像を取ったところで何の意味もない。そのため圏論では、定義域と値域をあわせて写像ではなく「射」という言葉を使ってる。たぶん。僕のこれまでの圏論の認識といえば「射で考えるやり方」という程度だったので、今日の講義でようやくさっぱりした)。
同じように任意の集合とそこからの任意の射を使うことで、単射に限らず数々の集合っぽい概念を再定義できる。ところで、たとえば直積がペアをあらわすように、集合の概念はデータ構造を形成できる。ってことは、圏でもやっぱりデータ構造を定式化できるよね。たぶん、これが今日の講義のメインだったんだと思う。


2時間で真似(まね)ぶ関数型言語のコンパイラ(講師:住井英二郎先生)

MinCamlの話は仕事や趣味からはいちばん近い話題で予備知識も多かったせいか、関心するところが多すぎてあまり扇動的な気分にはなれず……。実はこのサマースクールに参加した背景には、講義の内容から技術的な知見を得たいっていう以上に、精神的にアジテートされたいっていう動機があった。まあ、お前の求めてるものがおかしいって話なんですが。
余裕があったらまとめをかく。


述語抽象化によるアルゴリズムの検証 ~ シェープ解析を例として(講師:田辺良則先生)

プログラムの安全性を検証したいけどすべての状態と状態遷移を検証するのは無理だよね、それなら数学的に証明された方法で抽象化した状態とその遷移をうまく取り出して検証しましょうって話。まったく予備知識のない分野だったせいか、3時限目にもかかわらず異常に興奮した。プレゼンも面白い。
これも、余裕があったらまとめをかく。

2006/09/05

いよいよネタ切れか。とりあえず内部でプロシージャを定義するのを止めて、ついでに末尾再帰にだけしておこう。
(define (quicksort/values/cps ls k)
(if (null? ls)
(k '())
(quicksort/values/cps
(cdr ls)
(lambda (cdrls)
(receive (low high)
(partition (cut > (car ls) <>) (k cdrls))
(append low
(cons (car ls) high)))))))
昨日で一気にFPっぷりがあがった気がする。にしてもダサい名前のつけ方だ。

2006/09/04

急がないと歯医者に間に合わないけど、ひきつづきクイックソート。partitionかあ。ありがとうございます>nobsun
(define (quicksort/values ls)
(define (low-high ls)
(partition
(cut > (car ls) <>)
(cdr ls)))
(if (null? ls)
'()
(receive (low high)
(low-high ls)
(append (quicksort/values low)
(cons (car ls) (quicksort/values high))))))
気が付くと lambda がいない。

2006/09/03

Scheme Kata の続き。いちおう毎日ちょっとでも続けたいんだけど正直ネタ切れ。なんで初日に4つも作っちゃったんだろう……。
苦し紛れに昨日の多値を使ったバージョンをそのままreceiveを使って書き直す。hanataniさんに教えてもらうまでreceiveもcutも知らなかったから、苦し紛れとはいえ個人的な訓練にはなっているような気がする。Kata だからそれでいいじゃん。
(define (quicksort/values ls)
(define (low-x-high)
(values
(filter (cut > (car ls) <>) (cdr ls))
(list (car ls))
(filter (cut <= (car ls) <>) (cdr ls))))
(if (null? ls)
'()
(receive (low x high)
(low-x-high)
(append (quicksort/values low)
x
(quicksort/values high)))))

2006/09/02

Scheme Kata のつづき。多値でクイックソート。filter からは逃れられず。
(define (quicksort/values ls)
(if (null? ls)
'()
(call-with-values
(lambda ()
(values
(filter (lambda (x) (> (car ls) x)) (cdr ls))
(list (car ls))
(filter (lambda (x) (<= (car ls) x)) (cdr ls))))
(lambda (low x high)
(append (quicksort/values low)
x
(quicksort/values high))))))

2006/09/01

いまさら Code Kata をやってみようと思った。といっても Kata 1 はコードを書くわけじゃないのか。というわけで Kata 2 から。うーん、二分木の探索ねえ。めんどくさいので勝手にクイックソートに問題を変更させていだきます。でも4つしか思いつきません。しかも二個目は一個目からコピペしただけのいんちき。ほかにどんな方法があるんだろう。
(use srfi-1)
(define ls '(4 9 2 5 8 7 3 1 6 4))

(define (quicksort1 ls)
(if (null? ls)
'()
(append (filter (lambda (x) (> (car ls) x)) (quicksort1 (cdr ls)))
(list (car ls))
(filter (lambda (x) (<= (car ls) x)) (quicksort1 (cdr ls))))))
(quicksort1 ls)

(define (quicksort2 ls)
(call/cc
(lambda (k)
(if (null? ls)
k
(append (filter (lambda (x) (> (car ls) x)) (quicksort2 (cdr ls)))
(list (car ls))
(filter (lambda (x) (<= (car ls) x)) (quicksort2 (cdr ls))))))))
(quicksort2 ls)

(define (quicksort/cps1 ls k)
(if (null? ls)
(k '())
(quicksort/cps1
(cdr ls)
(lambda (cdrls)
(append (filter (lambda (x) (> (car ls) x)) (k cdrls))
(list (car ls))
(filter (lambda (x) (<= (car ls) x)) (k cdrls)))))))
(quicksort/cps1 ls (lambda (k) k))

(define (quicksort/cps2 ls k)
(if (null? ls)
(k '())
(quicksort/cps2
(filter (lambda (x) (> (car ls) x)) (cdr ls))
(lambda (ls-lower)
(quicksort/cps2 (filter (lambda (x) (<= (car ls) x)) (cdr ls))
(lambda (ls-upper)
(k (append ls-lower
(list (car ls))
ls-upper))))))))
(quicksort/cps2 ls (lambda (k) k))
Code Kata というより Scheme Kata?
どれも基本となる部分は filter で、芸がなくって本当にがっかりだ。いろんなバリエーションを考えるのが Kata 2 の目的な気がするんだけど。なんかもうこう完全にびっくりするぐらい違うのが思いつきたい。

2006/08/31

原稿を催促する側の気持ちが分かる人間は催促される側よりも少ないと思う。

YAMDAS現更新履歴 - 原稿を催促する人、締め切りを破る人
http://d.hatena.ne.jp/yomoyomo/20060831/deadline

「困るといわれても困る」になぜかとても理解があると勝手に自負している編集者としては、職場でほかの人がひたすら「原稿ください。こっちも困るんです」みたいな電話を繰り返していると、回線交換機を叩き壊したい衝動に駆られて困る。YAMADASさんが指摘しているように、そういう編集者は実際に「優秀な編集者」ではない。これはもう、編集者失格な僕がそう感じているんだから間違いない。

かといって、まったく催促がへたくそな僕のような編集者を雇っておくのは会社としては困るはずで、だから8月も最後の今日になると、「来年には発行する予定です」って報告している企画を上司に提示されて「この企画の進捗はどうなってるんだ」と絞られたりする。どうなってるんだといわれても困る。せっかく本を書くっていう儲からない(けど楽しい)仕事を引き受けようとしてくれている人達に「困るといわれても困る」内容のメールを出すのはしのびない。

それでも最後にはメールを書く。ほぼ定型文。1行目「進捗はどうでしょうか」 2行目「多忙のところお願いばかりで申し訳ありません。よろしくお願いします」 ただし、実際にはこの行間にちょっと何か具体的なことも書く。そして、そこに何を書いたらいいか分からなくて困る。ときには3日くらい困ってる。4日かもしれない。そして書いても出さないことがある。だってブログとか読むと忙しそうなんだもん。

オチがないけど、まあ原稿があって編集ができるんだから、僕もがんばらないといけないですね。