« 2007年02月 | メイン | 2007年04月 »

2007年03月31日

インターネット買った日記

インターネットどうやって買うのか 価格ドットコムで検索したら ちゃんと「電話線のない場合」も選択肢があった。

インターネットって高いねぇ。

価格ドットコムで一番安かったTEPCO光にしてみた。 インターネットって工事とかが必要なのかー。


=
僕は、金属工作を平岡氏の本を読んで学んだ。三十代のときである。この上なく緻密で丁寧で美しい図面と適切な説明が平岡氏の持ち味であるが、初めてこれを読んだとき、工夫さえすれば、時間をかけさえすれば、どんなものでも自分の手で作れるのだ、ということに気づかされた。

 平岡氏の本に従って、工具を1つずつ揃え、何日もかけて車輪を作った。これが庭園鉄道の夢の始まりだった。その後、走らせる土地が必要だと考えて、自分の貯金や収入では、一生できないかもしれない、と計算して、思い切ってバイトをすることにした。それが小説を書いた動機である。したがって、作家になったのは、平岡氏のおかげかもしれない。

MORI LOG ACADEMY: びっくりした荷物

意外な転職のきっかけ。


= 明日新居に5日分の着替えを持って行けば とりあえず第1週は問題ないかな。 第3週の終わりまでにすべて移動しないといけないんだけど。

今日は4時間くらいかけてだいぶゴミを捨てた。 トイレにため込んでいたトイレットペーパーの芯とか。 だって何かに使えそうだと思ったんだもん。 あとティッシュの箱とか。だってちょうどいいサイズなんだもん(何に?)


= ゴミ捨て場に未使用の引っ越し用段ボール箱が5つ捨ててあったので拾ってきた。

でも、僕の荷物は半分以上が本。重量比だと90%以上が本。 この段ボールに詰めると30キロを超えるよなぁ…。


= 腰が痛い。 頭も痛い。肩もこっていて、目も痛い。

2007年03月30日

immutableクイズ

空欄を埋めよ。
>>> dic = {}
(空欄)
>>> dic
{[1]: 1, [2]: 2, [3]: 3}
>>> for k in dic.keys():
	k.append(0)

	
>>> dic
{[1, 0]: 1, [2, 0]: 2, [3, 0]: 3}

答えは2通り以上あるけど、、どういうのとどういうの、っていうとヒントになるから言わない。

ファインマンが 「小学校の教科書で『電車はなぜ動くのでしょう?それはエネルギーが動かすからです』なんて説明はまずくないか?それを習った生徒が『エネルギー』という言葉なしで習ったことを説明できるか?できないのは、結局言葉の定義以外を覚えただけだからじゃないのか?」というようなことを言っていた。 で、(im)mutableという言葉を使わずになぜPythonの辞書にはリストが入れられないのかを説明できるだろうか?

初心者向けの解説で「リストはミュータブル(変更できる)ので辞書には入れられません」なんて説明をするのはやめたほうがいいのではないだろうか。

答えは30cm下で書く。

>>> dic = {}
>>> class Foo(object):
	def __init__(self, vs):
		self.value = vs
	def __repr__(self):
		return repr(self.value)
	def append(self, v):
		self.value.append(v)

		
>>> dic[Foo([1])] = 1
>>> dic
{[1]: 1}
>>> class Bar(list):
	def __hash__(self):
		return id(self)

	
>>> dic[Bar([2])] = 2
>>> dic
{[1]: 1, [2]: 2}
>>> class Baz(list):
	def __hash__(self):
		return sum(self)

	
>>> dic[Baz([3])] = 3
>>> dic
{[1]: 1, [2]: 2, [3]: 3}
>>> for k in dic.keys():
	k.append(0)

	
>>> dic
{[1, 0]: 1, [2, 0]: 2, [3, 0]: 3}
このように、辞書にリストを入れること自体は別に難しいことではない。 ではなぜ、わざわざ辞書にリストが入らないようにしてあるのだろうか?

id(オブジェクトの同一性)を使って区別をするFooとBarの場合、下のような現象が起きる。

>>> dic2 = {}
>>> dic2[Bar([])] = 1
>>> dic2[Bar([])] = 2
>>> dic2[Bar([1])] = 3
>>> dic2[Bar([1])] = 4
>>> dic2
{[]: 1, []: 2, [1]: 4, [1]: 3}
1つ目の[]と2つ目の[]は別物だから。 下のコードはエラーになる。
>>> dic = {}
>>> dic[Bar([])] = 1
>>> dic
{[]: 1}
>>> k = Bar([])
>>> k
[]
>>> print dic[k]

Traceback (most recent call last):
  File "", line 1, in -toplevel-
    print dic[k]
KeyError: [] # 1つ目の[]と2つ目の[]は別物なのでキーが見つからない

中身を見て区別をする(同じ中身のものは同じと見なす)ようにすると、 この現象は起こらなくなる。

>>> dic = {}
>>> dic[Baz([1, 2])] = 1
>>> dic
{[1, 2]: 1}
>>> k = Baz([1, 2])
>>> k
[1, 2]
>>> print dic[k]
1
しかし、中身で分類しているので、中身を書き換えられると困る。 中身の合計が3だから3の棚にしまったので 6の棚を探しても見つからない。
>>> k = dic.keys()[0]
>>> k
[1, 2]
>>> k.append(3)
>>> k
[1, 2, 3]
>>> dic
{[1, 2, 3]: 1}
>>> print dic[Baz([1, 2, 3])]

Traceback (most recent call last):
  File "", line 1, in -toplevel-
    print dic[Baz([1, 2, 3])]
KeyError: [1, 2, 3]
こうなったら書き換えられないリストを作るしかないんじゃない? というわけでタプルが生まれたのではないかと思う。

2007年03月29日

引っ越しまだしてない日記

今日はもう3月29日か! 3月ももう残りわずか!

明日転入届を出す。 免許の住所更新はどうしよう。

サンスベリア買おうかなぁ。 水やらないでいいし。


= 本屋で何気なく手に取った レバレッジ・リーディングという本。 これはよかった。

帯には「なぜ速読より多読なのか」というメッセージが書かれているけど、 フォトリーディングの「あなたもいままでの10倍速く本が読める」と言っていることはほぼ同じ。 著者は「1冊の本だけに書かれていることはその著者の意見かも知れないが、 複数の本に書いてあればそれは重要なポイントだろう」(だから同じトピックで複数の本を読め) と述べ、そういう読み方に「カテゴリー集中法」という名前をつけているけども、 これってフォトリーディングの「シントピックリーディング」と同じ。

結局のところ高速に本を読むためには「全部を読もうとせずに、重要なところだけ読む」 ということにつきるわけだ。そこまでは「10倍速く~」と同じ。 違うところは「捨てる技術」(笑)

今まで、本を買って読んでも、それで終わっていたわけだけど、 筆者のように年に何百冊も読もうとすると収納が追いつかない。 一度読んだ本を取っておいてまた読もうと思うからいけないのであって、 エッセンスを抽出した本は捨ててしまえ、という話。 逆に「エッセンスを抽出して捨てる」というつもりになれば 線を引いたり角を折ったりするのも抵抗がなくなる。

この本を読んで、一番感銘を受けたのは 「出がらしのお茶の葉と同じ」という言葉。 本ってものはそこから価値を引き出すために買うわけだ。 ざっと読んで80%の価値を引き出しても、 「じっくり読むと見つかるかも知れない残りの20%」が気になって捨てられないし、 いつか精読しようと思ってしまう。 そうじゃない、と。 80%取った後の本は出がらしの茶葉だと。 お湯を入れて時間をかければ薄いおいしくないお茶ができるかも知れないけど、 そんなのは捨てて新しい茶葉でおいしいお茶を飲んだほうがいい、と。 これが目から鱗だった。

というわけで読み終わったから巻末の「わたしのベストビジネス書」だけ破り取って 本はゴミ箱にほりこんだ。

安心して捨てるためには、 読んだ本の中の重要だったと思う部分をきちんとメモすべき。 「10倍~」では確かマインドマップを使うという話だったけど、 これは僕にはなじまなかったので結局やっていなかった。 しかし「読書後にメモを作る」という所は非常に重要。 ここを割愛したのは間違いだった。 この本ではパソコンを使ってメモを取っている。 メモの取り方は自分がやりやすいようにやっていいと書かれている。 でもパソコンを使ってメモを取れば、長い文章も辛くないし、 字が見やすいし、持ち歩いて読み返している間にぼろぼろになっても印刷し直すだけ。 検索もできるよね。 僕はパソコンでメモを取って、超整理手帳サイズ(A7を縦に2つ並べたサイズ)に印刷することにした。

フォトリーディングと何も矛盾しないよねぇ。


= さて、さっそく学んだことを実践してみようと買ってきたのが「TIME HACKS!」。

1時間で読むつもりだったのに、線を引くところがたくさんありすぎて8割しか読めなかった。 こういう「ノウハウぎっしり系」の本は線を引くところが多くなる傾向があるね。

途中ファイナンスにからめて書かれているところが、一部目から鱗でもあり、 一部「それは無理矢理だな」って所もあり。

とりあえずGoogleCalendar使おうかな。今まで 「管理するほどもスケジュールない。手帳で十分」と思っていたけど、 「15分程度の短いタスクもいつやるか決めて書き込んでしまう」 っての。 やりたいことは山のようにたまっているけど、手をつけないまま塩漬けになっているので、 時間を決めて着手してみるべき。着手してみると「すすめると面白そう」とか 「これはダメそう」とかわかるもんだしね。

著者は松竹のプロデューサーなのか…。実例にウノウとかGoogleとか出せるのがすごい。 知識の幅が広い。


= 本を読んで「おっ」と傍線を引くような内容には2種類ある。 レバレッジ・リーディングの著者は傍線を引いたところを繰り返し読むと言っていたけども、 たとえば「Googleカレンダーの仕事の所は赤にする(灰色だと気が滅入るから)」なんてのは 1回読めばそれでOKなわけだ。

荷物受け取り日記

起きた。

えええー。 このタイミングで浴室の電球が切れた…。 呪い?


= 11時頃に家に着いたらIKEAの不在配達票が10時25分。 もうちょっと早く家に着いていれば今日はソファーに座って作業ができたのだけど。 まぁいいや。

新居の写真

新居
新居 posted by (C)にしお

キッチンが広い。レオパレスと大違い。

キッチン
キッチン posted by (C)にしお

実家で余っていたので持ってきたカーテンは予想通り長さが足りない。

足りない…
足りない… posted by (C)にしお

ネットにつながるかどうか試そうと思ってLANケーブルを持ってきたのだけど、 このコンセントは電話線じゃないか!(当たり前)

インターネットってどこで売ってるんだろう。


= 日経新聞より。 ソフトバンクは第一子の出産祝い金が5万円、第二子が10万円、第三子が100万円、 第四子が300万円、第五子が500万円だそうな。すごいなー。 社員が子だくさんでも会社にとって直接のメリットはないのに。

子供の小学校入学時に子供向け携帯を無償配布し、 基本料金は無料にするそうな。 そして年5日まで運動会などでの休暇を取得できるんだそうな。

こういう話を聞くと、産休の取れない会社が学生に 嫌われるような時代が来るんだろうなぁという気がする。


= 家電が来た。 最近の冷蔵庫は運んできてすぐに電源を入れてもOKなんだな。

とりあえずオーブンを空焼きする。

ちゃんと130度の温度が出せるオーブン。 これで樹脂粘土いじりができる。

お腹が空いたので徒歩でイトーヨーカドーに行って、 冷凍食品半額セールなので喜んでたくさん買ってきた。 徒歩で冷凍食品が溶けない距離ってすばらしい。

食器がない。 唯一のお皿とティースプーンでピラフを食べる。


= インターネットはSFCってとこで買えるらしい。 WIDEとセットで買うのがおすすめらしい。 地デジ対応のWIDEとセットで買うのも悪くないかもなぁ。 SFCには自転車で行けると言われたけど、 WIDEを自転車に積んで走るのは怖いから郵送してもらうほうがいいと思った。
= 3時回ったのにまだ椅子が来ない。 早く来ないかなぁ。 腰が痛いよ。 あと、昼間暖かかったから油断したけど、やっぱり板張りの床に座っていると寒い。

まだかなー。

来た。

LYCKSELE
LYCKSELE posted by (C)にしお

LYCKSELE Manual
LYCKSELE Manual posted by (C)にしお

LYCKSELE
LYCKSELE posted by (C)にしお

組み立てた。

shinshuku
shinshuku posted by (C)にしお


= 今気がついた。 スーパーまですぐで、キッチンも広くて、自炊には最高だけど、 ここって外食はないな…。 強制的自炊。
= おおお、知らなかった。 M-/で補完が効くんだ、emacsって。 動的略語展開と言うらしい。 略語展開機能
= さて、6時か…。 原稿が進まないまま6時か…。 さて…。 帰るか、それともここに泊まるか…。

日記を更新したり撮影した写真をアップしたりウダーでスーダラ節を弾いたりしたいので、 帰らないことにしました。今日はここで原稿書きに専念。


= おおっ、ぴったり!

P1060982
P1060982 posted by (C)にしお

しまった。裏表逆だ。 まぁ、実害ないからいいか。

P1060984
P1060984 posted by (C)にしお


= 封筒を持ってくるのを忘れたことに気がついたので帰ろうかと思ったけど、 よく考えたら買えばいいだけなので買いました。 コンビニ近かった。

行きは迷ったので長く感じたけど、 改めて京成曳舟の駅まで行ってみたら3~4分だった。 そしてその道沿いにイトーヨーカドー、コンビニ、 郵便局がある。超便利じゃないか。


= マシンを膝に載せていると熱いので即席の机を作った。 ここに座ると軟禁状態。

P1060985
P1060985 posted by (C)にしお

やばい。この軟禁状態やばい。原稿を書く以外に何もできない。 唯一の娯楽がこうやって日記を書くこと。 一時的に日記の編集を禁止できないかなぁ。

2007年03月27日

引っ越し準備日記

やっぱり引っ越しの作業もろもろで原稿書きはあんまり進んでないなぁ。

記載事項変更(住所・本籍又は氏名の変更の方) :警視庁。 おっと、免許の変更には写真が必要か! デジカメで撮ってヨドバシとかの印刷機で印刷したやつでもいいのかな?

転入・転出の諸手続き。 年金手帳は転入手続きをするときにも持って行く。

電気の使用開始の手続き書類と、水道の使用開始の手続き書類はポストに入っていたので 書いて出した。 ガスはどうしたらいいんだろう。

東京ガスのサイトを見る。 東京ガス:ガスご利用ガイド/お引っ越しの際の手続き。 ああ、前日の手続きはネットではできない。昨日やっておくべきだった。

電話した。 問題なし。 ガスも明日開通することになった。 明日はIKEAからベッドが届いて、 ヨドバシから家電が届いて、照明と洗濯機を取り付けてもらえて、 お湯も出るようになる。 これでとりあえずいつでも住むことはできる。 後は本とか本とか本を4月20日までに運び出すだけ。

マツモトキヨシは錦糸町にある。 家から錦糸町までは、2キロくらい。 今の家から船橋までくらいの距離。

明日ガスとIKEAとヨドバシが早めに終わったら区役所に行こう。 終わらなかったら次の日でいいや。


= CBRCの納会。 原稿書きたくてお酒を控えめにしたのに、眠い。

明日は朝起きて、洗濯して干して、 郵送しないといけない書類を郵送して、 新居へ。

2007年03月26日

Python温泉日記

Python温泉というものがあるらしい。 「wxPython VS PyQt VS PyObjC」なんて企画があったので、 とりあえずJythonで殴り込みをかけてみた。
= 登 大遊@筑波大学情報学類の SoftEther VPN 日記。 「慣れ親しむことで、頭で考えなくても行動できるようになる」というのは確かにその通りだと思います。 車の運転とかもそうですね。 で「頭で考えて行動している状態」よりも「無意識的に行動している状態」のほうが生産性が高いというのも 同意できます。 フロー - Wikipedia状態になっている時は頭で考えている割合が低いように思います。

お酒を飲んだときにフロー状態になることも多いように思います。 そもそもプログラミングに論理的な思考が必須だったら、 お酒を飲んでコーディングするのは不可能に近いわけですが、 実際はコーディング自体は酔っていても可能です(むしろ生産性が高い)

なお、何人かの、作業効率が良いコンピュータ関係のことをやっている人と話したところ、大体は上記のようなことを (表現は異なるが) 普段から実践しており、それによって、平均的なレベルと比較して遥かに高い能力で作業をしているようである。
確かに。 言わんとしていることには賛同するけども、僕だったらああいう表現はしません。 登君は「意識的に頭を使う論理的思考/無意識的に行う感覚的思考」という対置で書いていますが、 僕は「論理的」という言葉は思考の方法ではなくて内容に使いたいです。 つまり「意識的な思考/無意識的な思考」という対置で、 プログラミングに慣れることで「論理的なプログラミングを無意識的に行えるようになる」 という表現をとるほうが僕好み。

そもそも論理的な思考はルールの数の少ないルールベースの処理なのだから、 脳内バイナリにコンパイルするのも比較的簡単なはず。 プログラミングに必要なある程度の論理的思考は、慣れれば 意識せずに実行できるようになるわけです。 車の運転になれると考えることが減ってしゃべりながら運転できるようになるようなもの。

問題は「慣れて頭を使わずに実行できるようになった」という状況が かならずしも「よい状況」とは限らないという所じゃないでしょうか。 例えばデータ打ち込みのような 単純な知的労働は慣れてくると頭を使わずにできるようになる というのは(プログラミングもそうだということがイメージできない人でも) イメージできると思います。 でも、その「頭を使わない作業」を長期間続けるのは 脳に対してよくないと思います。 なんせ頭を使っていないのですから。 頭を使わない作業を長時間やっていると、頭を使う能力は下がってしまうと思います。

データ入力の仕事に慣れたおかげで、頭を使わずに高速にデータ入力ができるようになった、 とそれはまぁ、それがお仕事なんだから悪いことではないのですけどもね。 僕としてはそういう「頭を使わない仕事」に従事するのは嫌いで、 何とかしてその作業を機械化できないか、とか、 慣れてない新入りバイト君の生産性を上げるためにはどうすればいいか、とか 頭を使う仕事がしたいわけです。

プログラミングの例で言えば、 10000行のコードを書く速度を上げるのではなくて、 その10000行のコードを生成するプログラムを設計することで 1000行のコードで同等のプログラムを作れるようにするとかね。 現在の自分に注目していると、頭を使って「1000行で記述できるようにするシステム」を 作るよりも10000行を何も考えずに作るほうが速いかも知れないけども、 それは将来の自分や他の人を視点に入れると逆に遅いかも知れません。

登君が「頭を使わない作業」に従事しているというのは、 世界全体にとっては損失なのではないかと…。


= ううむ。 機能は秋葉原に行って新居用の家電を買ったのだけど、 その時に普段のカバンじゃ重いからと手提げ袋で行動したせいで、 今日は手帳を忘れた。 今日出そうと思っていた水道や電気の書類も忘れた。 あと転入届を出さないといけないのもすっかり忘れていた。

そうか、手帳を忘れたから 自分の住所もわからない。

書類書き。 Wordは嫌い。


= 帰りの電車。Haskell。
data P2 = P2{x::Int, y::Int}
data P3 = P3{x::Int, y::Int, z::Int}
これが「定義が重複している」エラーになる。 当たり前だけどちょっと許し難い挙動。
= ACアダプタを忘れた。

2007年03月25日

IKEA日記

安藤美姫と上戸彩の区別が付かない僕ですが、 今日何気なくテレビをつけていてもう一つ「区別が付かない組み合わせ」を発見。

ほしのあき - Google イメージ検索 はしのえみ - Google イメージ検索あやや - Google イメージ検索

20021226hayaya2.jpg (JPEG 画像, 405x304 px) hosinotop.jpg (JPEG 画像, 350x250 px) 2000007556.jpg (JPEG 画像, 200x200 px) 54e65681f876e30bdba9.jpg (JPEG 画像, 400x375 px) 。 ううむ。

安藤美姫と上戸彩の区別には「フィギュアをしていれば安藤美姫、してなければたぶん上戸彩」 という手が使えたのだけど。 とりあえずGoogleイメージを眺めた感じだと 「歌を歌っていれば松浦亜弥で、 胸の谷間を強調していたらほしのあき、 ちょっと年上な感じがしたらはしのえみ」かな。

はしのえみは33歳。ほしのあきは30歳、松浦亜弥は20歳?! ほしのあきと松浦亜弥は同じくらいの年かと思ってた。 ほしのあきが若く見せるのがうまいんだろうな。

そして僕はもしかして髪型で人を識別しているのか?


= 新居に行ってきた。 渡された鍵が足りてなくて 入り口のオートロックを入れない罠。
= 通りがかりに見たペコちゃんは首が取れてバネが出ていた。
= IKEAでソファーベッドを買った。 折りたたみベッドで、折りたたむとソファーになる。 ソファー形態とベッド形態のトランスフォーム時に バネがカショーンと鳴ってとても萌える。
= あと木の板を買いました。
= MORI LOG ACADEMY: 滑り台の問題
滑り台があって、高い位置のA点から、低い位置のB点まで、滑っていく。このとき、AB間を直線で結んだ滑り台と、やや、下に撓(たわ)ませた曲線で結んだ滑り台とでは、どちらが、滑り降りる時間が長くかかるだろう?
極端な例を考える。逆を考える。 「まっすぐな滑り台と スタート直後に超急降下する滑り台を比べたらさー、 超急降下する滑り台は最初で超加速してなだらかなところに来ても速いから、 超短時間じゃね? 逆にさー、上にばりばりたわんだ滑り台はさー、 ぜんっぜん進まなくてマジむかつかね?」

「位置エネルギーを運動エネルギーに変えた方が速く進むので、 地面に近い位置を走るコースのほうが速い」

でも、摩擦は考えないけれど抗力は考えるので、 下にたわんだコース(傾きの変化が正のコース)は、 コースが曲がるせいで余計に抗力を受けてエネルギーを失うように思う。 だから「位置エネルギーを運動エネルギーに変えたほうが~」という説明は片手落ち。 極端な場合、スタート直後に真下に落ちてその後平らなコースでは、 確かに位置エネルギーが最速で運動エネルギーに変換されて、加速はぴかいちなんだけど、 90度のカーブに衝突して止まってしまう。 抗力のせいですべての運動エネルギーが失われるわけだ。

本当の最速コースはどういう形なんだろうか。

昔何かで読んだ気がしたので調べてみた。 Brachistochrone Problem -- from Wolfram MathWorld

In fact, the solution, which is a segment of a cycloid, was found by Leibniz, L'Hospital, Newton, and the two Bernoullis.

2007年03月22日

Haskell In Python ver. 0.01

Haskellのコードを呼び出すための Pythonモジュールを作ってみました。

使い方。

>>> from Haskell import Haskell
>>> h = Haskell("""
func = reverse
func' x = map (+ x) 
value = 42
""")
>>> h.func
<Haskell.HaskellFunc object at 0x0153AC90>
>>> range(5)
[0, 1, 2, 3, 4]
>>> h.func(range(5))
[4, 3, 2, 1, 0]
>>> type(_)
<type 'list'>
>>> func2 = h.get("func'")
>>> func2(1, range(5))
[1, 2, 3, 4, 5]
>>> h.value
<Haskell.HaskellFunc object at 0x0153AD90>
>>> h.value()
42
>>> type(_)
<type 'int'>

仕組み。

PythonからHaskellを呼ぶためには、

  • 1:PythonのオブジェクトをなんらかのHaskellが扱える形に変換
  • 2:変換したモノを何らかの方法でHaskellに渡す
  • 3:Haskellが渡されたモノをHaskellのオブジェクトに変換
  • 4:Haskellが処理
  • 5:処理の結果のHaskellオブジェクトをPythonが扱える形に変換
  • 6:変換したモノを何らかの方法でPythonに渡す
  • 7:Pythonが渡されたモノをPythonのオブジェクトに変換
という手順を踏みます。

このバージョン0.01では

  • 1:Pythonのオブジェクトをstrを使って文字列に変換
  • 2:変換した文字列をソースコードに埋め込んでHaskellを実行
  • 3:Haskellパーサが文字列をパースしてHaskellのオブジェクトを作る
  • 4:Haskellが処理
  • 5:処理の結果のHaskellオブジェクトをshowで文字列に変換する
  • 6:文字列を標準出標準出力に力に吐いて、Pythonがそれを拾う
  • 7:Pythonが文字列をevalしてPythonのオブジェクトに変換
という感じになっています。 変換処理をそれぞれの言語の処理系に丸投げしたので40行程度でかけました。
= 既知の問題点。

  • 5番の変換にshowを使っているのでShowのインスタンスでないとPython側に渡せない。 また、Showのインスタンスであって、Python側に渡せたとしても7番の変換でこけるケースがある。
    • 例えば関数はShowのインスタンスでないので渡せない
    • 例えば「Just 1」はShowのインスタンスなので渡せるけどevalできない
    • 解決法:
      • たとえばPythonizableというクラスを作って、Intなどをそのインスタンスにする。
      • toPython :: (Pythonizable a) => a -> String を作る
  • HaskellでPythonの関数をpureな関数として扱えない
    • Pythonと通信するためにIOモナドになってしまうから
    • Haskellのコードで記述するのではなく、なにか拡張を作ってHaskell処理系をだましてやる必要がある

=
'''
  Haskell In Python

USAGE:
code = """
func = reverse
func' x = map (+ x) 
value = 42
"""

h = Haskell(code)

print h.func(range(5))
print h.get("func'")(1, range(5))
print h.value()
'''
__all__ = ["Haskell"]
class Haskell(object):
    def __init__(self, code):
        self.code = code
        
    def __getattr__(self, name):
        return HaskellFunc(self.code, name)
    def get(self, name):
        return HaskellFunc(self.code, name)


class HaskellFunc(object):
    def __init__(self, code, name):
        self.code = code
        self.name = name
    def __call__(self, *args):
        argsStr = " ".join(str(arg) for arg in args)
        f = file("tmp.hs", "w")
        print >>f, self.code
        print >>f, "main = print $ %s %s" % (self.name, argsStr)
        f.close()
        from popen2 import popen3
        (o, i, e) = popen3("runghc tmp.hs")
        err = e.read()
        if err:
            raise RuntimeError(err)
        return haskellStr2pythonObj(o.read())


def haskellStr2pythonObj(s):
    return eval(s)

Befunge日記

Befunge - Wikipedia。 なるほど、これも「ループに特殊な命令を必要としない言語」だな。 存在は何となく知っていたけど詳しい言語仕様は今回初めて読んだ。 Brainf*ckより面白い。

5時間あればBefungeインタプリタとBefungeで書かれたKEMURIインタプリタを作れると思うけど、 3倍で見積もった上で、今15時間かけて作るべきかと考えると…。

…。

「やりたいことはいくらでも沸いてくるけども、やる時間は有限なので 何かを捨てなきゃいけない。」

でも「精神衛生を保つために息抜きが必要だと割り切って、 遊ぶときにはしっかり遊ぶ」

ううむ。

とりあえず昼間から遊ぶのはダメだと思う。 しっかり働いてから遊ぼう。

でも今日遊ぶならウダーの練習がしたいなー。

というわけでBefungeはなし。


=
v @_       v
>0"!dlroW"v
v  :#     <
>" ,olleH" v
   ^       <
v @_^      
>0"!dlroW"v
v  :#     <
>" ,olleH"v
   ^<     <
にした方が1マス縮まるし、無理に再利用しないで
v      
>0"!dlroW"v
v  :#     <
>" ,olleH"v
 ,:!#@_   >
ってやれば
0"!dlroW"v
v    " " <
>",olleH"v
 ,:!#@_  >
0"!dlro"v
v ", W" <
>"olleH"v
 ,:!#@_ >
、とだいぶ小さくなると思う。 でも机上プログラミングなのでバグが入ってるかもしれない。 やっぱりスタックの中身とかいろいろな情報を表示しながら 実行してくれるツールが欲しいな。
= 淡々と執筆(いつものごとくエンジンがかかるまでに時間がかかったけど)

3-0 done 3-1 done 3-2 done

安西先生、Haskellがしたいです…

Jython本なので当然 Java+Pythonの話だけをしているわけだけど、 もちろんJava+RubyでもJava+JavaScriptでもいいことは知っているわけで。 なんかもう、Jython本を書き終わったらJavaとPythonをしばらく封印して、 FlashとActionScriptでGRINEdit的なものを作ってみたいような。

自分の性格がよくわかった。自分は一つのテーマを長時間ずっとやるのは苦手だ。 HaskellとかActionScriptとかBefungeとかしたいぞーーーー。


= 晩ご飯を食べながら思いついたことを、忘れないうちに試してみた。

西尾泰和のブログ: Haskell In Python ver. 0.01

いちおう期待通りに動いている。 イメージだけよりも、やっぱり具体的なモノがあった方が色々わかる。 0.01ではPythonの関数をHaskellから呼ぶことはできないけど、 モナドとしてなら実現は難しくない。Pythonで書いた関数を純粋な関数として扱うためには もうちょっと僕がHaskellの中身を理解していないと作れない。

でもまあ40分で書いた31行のコードなので、それなりなことしかしていません。 だからver 0.01。


= PyStringをStringに変換しないといけない、という話題。 自分がJythonの単なる一ユーザーの時は、 「そっか、変換しないといけないんだな」 で済んだのだけど、 それを人に解説すると 「あれ、でもどうして変換の必要があるんだ? 変換の必要のない実装は不可能なのだろうか?」 と考えるハメになる。

PyStringというクラスを導入せずにStringで押し切ることは不可能なのだろうか? 押し切るとどういう不都合が起きるのだろうか? 今の実装はPyString extends PyObjectだけど、 PyString extends String implements IPyObjectじゃダメなんだろうか、


= 秋元@サイボウズラボ・プログラマー・ブログ: JavascriptによるC系ソースコードのハイライトライブラリgoogle-code-prettify。 入れた。 PythonのIDLEのカラーリングとは一致はしない。 たとえばifやprintなどの予約語と、 あらかじめ用意してあるけども予約はされていないので上書きしてもいいintやTrueなどは、 IDLEでは区別されるけども、これでは区別されない。 両方ともキーワードという扱いになる。 あとdefやclassで新しく定義する名前は、IDLEでは青く着色されるけど、 これでは「普通のコード」と判定されて着色されない。 spanタグ自体がIDLEの着色方法と対応していない付き方をしているので スタイルシートをいじってもどうしようもない。

でも、まぁ許容できる範囲の違いかな、と思う。 もともとまったく色の付いていないのでも許容していたし。

西尾泰和のブログ: Haskell In Python ver. 0.01 のように、「コードのように見える文字列」がある場合は、着色前よりだいぶ見やすくなるね。


= Haskellはなんか名前の衝突が起きやすいのが嫌だなぁ。 下の二つのcodeが衝突する。 Situationから値を取り出す関数codeは、 Situationを引数に取らないと意味がないわけだから、 文脈で二つのcodeを区別できそうなのにね。
code = [
  "0\"!dlro\"v", 
  "v \", W\" <", 
  ">\"olleH\"v", 
  " ,:!#@_ >"]

data Situation = Situation {
  code::[String], pos::Pos, dir::Dir, textMode::Bool, skipMode::Bool}

= ちょ、Haskell、
data Foo = Foo{x :: Int}

main = print $ x $ (Foo -1)
これが
test.hs:3:20:
    Couldn't match expected type `Foo'
           against inferred type `Int -> Foo'
    In the second argument of `($)', namely `(Foo - 1)'
    In the second argument of `($)', namely `x $ (Foo - 1)'
    In the expression: print $ (x $ (Foo - 1))
こういうエラーになるのはひどい…。 -1くらい整数のリテラルとして認めてあげてよ…。 それかせめて整数の符号を反転させる演算子「-」の優先順位を、 関数の適用よりは上にしてよ…。
= 行方不明だった万歩計、お台場にあった!

本とかを持って帰るために来たのに、手提げ袋を忘れた。

火曜日にもまた来ることになったし、その時でいいかな。


= ラボの机をだいぶ片付けた。 19時。 Shibuya.esが始まるのでとりあえずfreenode.netに入ってみた。 ネット中継のリンクがまだ現れない…。

ふむふむ。FlashもJavaScriptでHTMLをいじる時みたいなツリー構造でいじれるのか。

小さくて更新頻度の高い画像と、 大きくて解像度の高い更新頻度の低い画像とが表示されている。 大きい側でスクリーンを拡大して表示するらしい。 これはなかなかよさそう。

Macromedia - Flash TechNote : fl0277 - ローカル Shared Object とは。 これを使えばローカルにいろいろな値を保存しておくこともできる。

akihiro kamijo: E4X。 ECMAScript for XML。 ドット接続で要素名がつなげられるし、ハッシュっぽいアクセスの仕方もできる。

わーお、「..」ってなんだー。 指定したのの直下に限らず、ってことだろうか。あてかん。

腰が痛くなってきた。

「Firebugがあればどんな複雑なCSSだってなんとかなる。」byはまちちゃん

ABC (ActionScript Byte Code) → MIR → x86

Shibuya.jsはプレゼンツールを自作してくる必要がある →手書きプレゼン(へた字)

「fcwrapを使え」

あまりの面白さに吹き出してしまった。 みんな帰った後でよかったw

haXe

alertがヒューマンリソースを食いつぶす。

document.cookieは共有されるので…おおおお。

Radium Software


= Haskellはパターンマッチで関数fooの定義を書いている間で関数barの定義をすると その後のfooの定義でmultiple declarationエラーになる。 かといってそこで使っている関数を関数fooの定義の後ろまで持って行くと、 離れてしまって見やすくない。 そこでwhereでくっつけてみたら、結局関数barを定義する必要がないじゃないかと。 可読性は下がった。

そうも行かない。 barが1カ所でしか使われないのならくっつけてしまうのもアリだけど 下のようなケースではどうしたらいいんだ。

(doCommandの定義がたくさん 略)
calc2 w f = let (u:v:rest) = stack w in
           w{stack = (f u v):rest}

doCommand '+' = calc2 (+)
doCommand '-' = calc2 (-)
doCommand '*' = calc2 (*)
doCommand '/' = calc2 (/)
doCommand '%' = calc2 mod
doCommand '`' = calc2 $ \x y -> if x > y then 1 else 0

= とりあえず行きの電車の中とShibuya.es聞きながらの内職で
main = return startWorld >>= dump >>= step >>= dump
ってやると
X"!dlro"v
v ", W" <
>"olleH"v
 ,:!#@_ >
0 []

0X!dlro"v
v ", W" <
>"olleH"v
 ,:!#@_ >
" [0]
と表示されるようになりました。 もう帰ろうっと。
= 帰りの電車がなかなか来ない。

テキストモードにはいるのは実装していたけど抜けるのを実装していなかった。

完成。

ああっ、 befungeにXOR命令はないじゃん。 加減乗除とかでXORを実装しないといけないのか。 コードの一部を書き込み用のスペースにして 自力で10進数から2進数に変換したりしないといけないのかな。

とりあえず5時間で完成するコースではなく、 15時間かかってしまうコースであることがはっきりしたので、 befungeでKEMURIを作るのは無期限で延期。

未踏ユースブースト会議日記

この前の尾藤さんの成果報告会の記事を見て 「ブースト会議ではあんまり内容に触れないで、 成果報告会が終わってから触るようにしたほうがいいのかもなぁ」 と思ったので、今回はあんまり書かない予定。

ウノウラボ Unoh Labs: 2006年度上期未踏ユース成果報告会に参加してきました

追記。全員分書いたのだけど、だいぶ削りました。

さらに追記。 やっぱり、別にそこまでして公開することもないので外部へのリンク以外公開しないことにしました。


= BCN ITジュニアの群像

BCNランキング :: BCN ITジュニア賞 :: <ITジュニアの群像 IPA未踏ユースへの挑戦>第36回 IPA未踏ユースへの挑戦


= 3Dプレゼンテーションソフトウェア「prezvision」


= Characters

TT's Origami Page

2007年03月19日

執筆プロトタイピング日記

はっ。 部屋の掃除が 4月にはいると平日いないから やりにくくなるってのと同様に、 引っ越しもやりにくくなるじゃないか。 今頃気がついた。

どうしようかな。


= また何から先にやるか悩んでしまう。 3章と4章と7章を行ったり来たり。 まずは3章を仕上げよう。

気を抜くと悩みの泥沼に片足をつっこんで、 原稿を書かずに「どう書くべきか」と自問し続けてしまう。 プログラミングにたとえるならば、 コードを書かずにどう書くべきかを悩んでいる状態。 どう書くべきかを考えることは悪くはないのだけど、 時間をかけてもそれが進まないということは、 足りていないのは時間ではなくて知識だ。 まずは実際にコーディングをして、問題に対する知識を増やすべき。

というわけでプロトタイピング。 とりあえず動くモノを作る。 あっちゃこっちゃ書きかけの状態は、 コンパイルエラーだらけの状態。 一度に全部作ろうとしない。 1~3章だけまずコンパイルエラーがなくなるようにする。

コンパイルエラーがなくなったら、実行してみて挙動を観察する。 つまり、文章としての体裁が整ったら、読んでみる。

プロトタイプのコードは、 捨てることを惜しんではいけない。

まずは3章のコンパイルエラーをとる。

淡々と作業せよ。

ゲーム脳とはゲームに時間を割きすぎることで、 「ゲーム以外の作業によって鍛えられる能力」が鍛えられていない状態だとすれば、 僕は「プログラミング脳」に違いない。

プログラミングの場合コンパイルエラーが懇切丁寧に一覧表示されるので、 上から順番につぶしていくだけでいい。 タスクの優先順位を考えたりしなくていい。 タスクに依存関係がある場合もあるけども、 必ず根があるので一番上の問題を深さ優先で探索して解決すればいい。

これに慣れてしまったせいで、 並列実行すべき複数のタスクがあると混乱する。 原稿が完成するまで深さ優先で作業をしたいんだけど、 それをやると何かが犠牲になる。引っ越しが間に合わないとか。

とりあえず明日未踏ユースのブースト会議があることは きちんと理解しているのでご安心を>関係者のみなさん


= 人生のタスクすべてが、修正すべきErrorと、 修正した方がいいWarningとにわかれて一覧表示されていたら楽なんだけど。

「彼女ができません、どうしたらいいですか」 「NullPointerExceptionがあちこちで起きています、 設計がそもそも間違っているかも知れません」 「ええー(涙)」 という会話が街角の占いとかでされるようになる。

「『彼氏』モジュールを変えたら、とたんにあちこちでClassCastExceptionが…」 とか。

本に載せるソースコードなどをどういう名前にしたらいいか。 これは単純にソフトウェアを作るときとはまたひと味違う。

Pythonにはパッケージ宣言がないので、 同じ名前のファイルがあるとどこのファイルかややこしい。 コメントで宣言すべき。 コメントでどのJavaファイルから呼び出されるスクリプトかとか書いた。

(global-set-key "\C-v" 'yank) AmetMultiを使うのでMeadowのキーバインドを変更。 ソースコードをコピーして「ぎょ」と入力してAmet変換すると、 行番号付きで挿入される。

最初から最後までみっちりやるのは疲れる。 まずあっさりバージョンで全体像をつかんでから、 時間と興味のあるときにみっちりバージョン。

あっさりバージョンをどんどん削って、 みっちりバージョンをどんどん上塗り。


= 明日しゃべる内容はまったく作ってないけど、 Jythonインタラクティブハッキングのショートバージョンのつもり。

2007年03月18日

モナドを作るver. 0.1

IOモナドは難しそうだったのでとりあえずMaybeモナドからはじめる。
>>> def Maybe(typ):
	class Foo(object):
		@classmethod
		def return_(_, x):
			return Just(x)
		@classmethod
		def bind(_, m, f):
			if isinstance(m, Nothing):
				return Nothing()
			elif isinstance(m, Just):
				return f(m.value)
	class Just(object):
		def __init__(self, x):
			assert isinstance(x, typ)
			self.value = x
	class Nothing(object):
		pass
	Foo.__name__ = "Maybe_%s" % typ.__name__
	return Foo
これで型を受け取って型を返す関数ができました。 Maybe Intみたいに呼び出してみよう。
>>> Maybe(int)
<class __main__.Maybe_int at 0x00D750F0>
「Maybe Int」型ができました。
>>> MaybeInt = _
>>> MaybeInt.return_(1)
<__main__.Just object at 0x00D57F70>
「return 1」で「Just 1」ができます。 「MaybeInt.」と書かないといけないのは、Pythonに 引数の型の情報を使って適切な関数を選択する機能がないから。

適当な関数を作ってbindしてみましょう。

>>> def inc(x): #:: int -> Maybe int
	return MaybeInt.return_(x + 1)

>>> MaybeInt.bind(_, inc)
<__main__.Just object at 0x00D57A90>
>>> _.value
2
できました。

でも、これじゃIOモナドには進めません。 なぜかというと、x + 1の計算がbind時に行われているから。 ここの評価を遅延させる必要があります。

>>> class Lazy:
	def __init__(self, expr):
		self.expr = expr
		self.value = None
	def force(self):
		if self.value == None:
			print self.expr, "を評価します"
			self.value = self.expr.force()
		return self.value
	
>>> class Literal:
	def __init__(self, value):
		self.value = value
	def force(self):
		return self.value

>>> class LazyAdd(object):
	def __init__(self, a, b):
		self.a = a
		self.b = b
		self.value = None
	def force(self):
		if self.value == None:
			self.value = self.a.force() + self.b.force()
		return self.value

>>> def inc(x): #:: int -> Maybe int
	return MaybeInt.return_(LazyAdd(x, Literal(1)))
これで試そうと思ったのですけど、 intをLazyで包んでしまうと、 MaybeIntの型チェックで「intじゃなくてLazyだ」と怒られてしまうので 型チェックを削除。

ああ、でも本当は 「評価前」「評価後」という2状態じゃないんだなぁ。 パターンマッチの書かれ方によって、 どこまで評価するかが決まるのか…。

IOで「入力用モナドと出力用モナドをつなぐだけでwhileも書いていないのに ループしてくれる」 というような説明があるけども、 それは入出力用のモナドの中の実装が見えていないから魔法みたいに見えるだけ。

>>> def printStr(x):
	while True:
		v = x.force()
		if v == "[END]":
			break
		print v

		
>>> def inputStr():
	class LazyInput:
		def force(_):
			return raw_input()
	return LazyInput()

>>> printStr(inputStr())
111
111
222
222
[END]
このコードの「printStr(inputStr())」だけ見せられれば、 そりゃ魔法みたいにも見える。

2007年03月17日

モナドはごちそうさま日記

問い。下の2行が同じ出力になるようにjoinを定義しなさい。
-- main = putStr $ unlines $map show [1..5]

main = join (map print [1..5])

IO()だから()を捨てても問題がないわけだな、とか。 元からモナドだからreturnしなくていいんだな、とか。 >>=はモナドとモナドを直接つなぐことはできないんだな、とか。 つなぎ目の形を合わせるために間にラムダを挟むんだなぁ、とか。

解答。

join :: (Monad m) => [m a] -> m a
join [x] = x
join (x:xs) = x >>= (\a -> (join xs))

ようするに、どこでも節操なくIOできるPythonとかと違って、 Haskellは最終的にmain::IO()がIOするので、 IOするモナドをつなぎ合わせて大きなモナドにしてmainに入れてやるしかない。

「モナド」「モナド」と言葉が一人歩きしているけど、そのモナドって どういうたぐいのものなのか。 モナドというデータ型なのか、モナドという制御構造なのか、 モナドというデザインパターンなのか。

MonadはEqやOrdと同じたぐいの「型クラス」で、Javaにたとえるならインターフェイス。 JavaでRunnableをimplementsしないとスレッドで実行できないのと同じで、 HaskellではMonadをinstanceしないとIOできない。

「Monadのインスタンスはbindやreturnをモナド則に従って実装せねばならない」 ということが大げさに感じられるけども、 Eqのインスタンスだって==をいろんな法則に従うように実装しないといけない。 まず「x == x」が常にTrue。次に「x == yがTrueの時、y == xは常にTrue」。 最後に「x == yがTrueで、y == zもTrueの時、x == zは常にTrue」。

Eqが満たすべき法則を書いてみると、当たり前すぎて何を今更という感じがする。 でもこの法則を満たさない==を実装したら、いろいろなアルゴリズムが予定外の挙動をするだろう。 モナドがモナド則を満たさないといけないのも同じこと。 モナド則を満たしていると仮定して他のアルゴリズムが実装されているので、 そのルールを守りましょう、ということ。


= さて、モナドがわかった気分になったところで、僕はそろそろ執筆に戻らなきゃ。 柴田さんいわく、執筆はマラソンとのことで、 この2,3日Haskellというおもちゃにどっぷりはまってしまった僕はたとえていうなら、 マラソンの最中にミスタードーナツに入ってエンゼルクリーム(モナド)を食べて一服していたら、 なかなか走り出せなくなってしまったような状態。

まず靴を履いて、外に出て、ゆっくりでも進まなきゃ。 まずは今までに書いた原稿を音読。

はっ。ミスタードーナツは略してミスドか。 モナドはモナードーナツか。 なんかすでにAAまでありそう。

はてぶのコメント

モナドナルドかもしれないと思った
なるほど。モナドナルド。たしかにそれもあり。

関東人はモッナとか略すんだろう。 名前がモナで名字がドナルドだとか思ったら大間違いだ!


= /halt/Snapshot - 先月予約したものが届いた おおお、売ってるものだったのか。

Amazon.co.jp: THE JAPANESE TRADITION ~日本の形~: DVD: ラーメンズ,NAMIKIBASHI,斉木しげる,山咲千里。 そして見たことのない動画がいっぱいあるっ。 これはっ。

YouTubeで見られる「鮨」や「土下座」はオフィシャルに公開しているものだそうな。 あれだけしかアップされてないからてっきりあれだけしかないものと勘違いしていた。

我々日本人は自国の文化についてもっと知るべきである
大賛成。
= やりかけた作業を明日の自分に伝えるメモ。 一段落付くところまでやり終えて(朝の5時とかになって)疲れて寝るのではなく、 次にやることが見えている状態でやめるのがいい。 …って誰かが書いていた。

ぐぐったけど誰が言ったのかわからなかった。 でも生産性向上のテクニックとして有名なようだ。

HaskellでBrainf*ck

書いちゃった。

Brainf*ckは、テープを破壊的に書き換えまくったり、 特定のコマンドが来たときには入出力を行ったり、と Haskellで書きにくそうな問題だ。 基本的にWorldという「ポインタの位置」「テープ」「実行すべきコード」「スタック」 の4つがセットになった型のオブジェクトを iterateのようなもので何度も何度も呼ぶ設計にしていたのだけど、 IOをする段になって悩む。

結局(IO World)というIOモナドで包んだ世界にしてやって、 いままで単純にWorldを返していた部分はreturn Worldに置き換える必要があった。 入出力をする部分は、getCharやputStrのような入出力をする命令とreturn Worldをbindして やる。

入出力周りは理解するまでが大変だったけども、 書いてみると行数的にさほど手続き型言語より面倒かというとそうでもないような。

7行割いている下のコードはライブラリにありそう。デフォルト値付き連想配列。

data VPair = V {pos::Integer, val::Integer} deriving Show
type Tape = [VPair]

getHead [] = 0
getHead (x:xs) = val x
getV tape p = getHead $ filter ((p ==).pos) tape
setV tape p v = modV (\x -> byte v) tape p
modV f tape p = (V p (byte (f (getV tape p)))):(filter ((p /=).pos) tape)

=
ループの処理は、
 開きかっこが実行されたときに
  ポインタの指す値が0だったら、
   閉じかっこの次までソースコードを捨てる
  非0だったら
   「残りのソースコード」をスタックに積み、
 閉じかっこが実行されたときに
  スタックの先頭のコードを戻す
cond_exec w@(World p t c s) =
  if getV t p == 0 then
    w{commands = skipCommands c}
  else
    w{stack = c:s, commands = tail c}

jump_back w@(World _ _ _ (s:ss)) =
  w{commands = s, stack = ss}

skipCommands (']':cs) = cs
skipCommands (_:cs) = skipCommands cs
読みやすい。
= ところで「仕様を記述するだけでプログラムになる」 とかいうけども、その仕様を決めるところが一番難しいんじゃないかと思う。 余談。
= 繰り返し実行する部分は、iterateMが存在しなかったのでfoldMのソースコードを見ながら実装。 1つめの処理に次の処理をbindして…とやっていく。Pythonの
w = newWorld
while True:
    w = step(w)
    if w.commands == "": break
に相当するコードが
iterateM f w =
  if (commands w == "") then
    return ()
  else
    f w >>= \nextW -> iterateM f nextW 

main = iterateM step newWorld
になる。

iterateMは終了条件をくくりだせば汎用の関数になるなぁ。 iterateM step ((== "").commands) newWorldの1行で済むようになる。


= 機械語にコンパイルできる言語で、静的な型チェックもあるのに、 これだけ楽に書けるというのは、確かにすごいことだとは思う。 でもプロトタイピングに役に立つかというと微妙。 プロトタイピングにはPythonの方が楽な気がするし(僕が慣れているというだけかも)、 仮にHaskellでプロトタイプを作ったとして、 それをCやJavaに移植するのはかなり面倒だろう。

KEMURIがPythonの半分の行数で書けて萌えたのだけど、 あれはIOがないから簡単に書けたのだ。

仕様がすでに明確に決まっていて(パズルとか)、 IOやユーザとのインタラクションがなければ(インタラクティブでないプログラムなら)楽。 というか、HaskellでGUIを作ったとしたら、メインループでモナドを使う必要があるから、 既存のGUIライブラリのほとんどは使えないわけだなぁ。


=
=
import Data.Char

data World = World {
  data_p::Integer, tape::Tape,
  commands::String, stack::[String]
} deriving Show

data VPair = V {pos::Integer, val::Integer} deriving Show
type Tape = [VPair]

test1 = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++."
test2 = "++++++++[>++++++++<-]>+."
test3 = "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."

newWorld = World 0 [] test3 []

getHead [] = 0
getHead (x:xs) = val x
getV tape p = getHead $ filter ((p ==).pos) tape
setV tape p v = modV (\x -> byte v) tape p
modV f tape p = (V p (byte (f (getV tape p)))):(filter ((p /=).pos) tape)

inc = (+ 1)
dec = (subtract 1)
byte n
  | n < 0 = n + 256
  | 255 < n = n - 256
  | otherwise = n

mod_data f w@(World p t _ _) = w{tape = modV f t p}
inc_data = mod_data inc
dec_data = mod_data dec

mod_ptr f w@(World p _ _ _) = w{data_p = f p}
inc_ptr = mod_ptr inc
dec_ptr = mod_ptr dec

cond_exec w@(World p t c s) =
  if getV t p == 0 then
    w{commands = skipCommands c}
  else
    w{stack = c:s, commands = tail c}

jump_back w@(World _ _ _ (s:ss)) =
  w{commands = s, stack = ss}

skipCommands (']':cs) = cs
skipCommands (_:cs) = skipCommands cs

step w@(World p t (c:cs) s) = case c of
  '+' -> dump (inc_data w){commands = cs}
  '-' -> dump (dec_data w){commands = cs}
  '>' -> dump (inc_ptr w){commands = cs}
  '<' -> dump (dec_ptr w){commands = cs}
  '[' -> dump (cond_exec w)
  ']' -> dump (jump_back w)
  ',' -> input_data w
  '.' -> print_data w

dump :: World -> IO World
dump w = return w
{-
dump w =
  do print w
     return w
-}


print_data :: World -> IO World
print_data w@(World p t cs _) =
  do putStr [chr $ fromInteger $ getV t p]
     dump w{commands = tail cs}

input_data :: World -> IO World
input_data w@(World p t cs _) =
  do c <- getChar
     dump w{tape = setV t p (toInteger (ord c)),
            commands = tail cs}

iterateM f w =
  if (commands w == "") then
    return ()
  else
    f w >>= \nextW -> iterateM f nextW 

main = iterateM step newWorld

Haskellのモジュールがよくわからない日記

今日はもう金曜日か。勘違いしていた。
= 予算は無事使い切れそう。 あまったらLANケーブルとかOAタップとか買おうと思っていたけど、 秘書さんが文具を買うというので面倒だから任せることにした。 自分のお金じゃないので気前がいい。
= ITmedia Biz.ID:理想のファイル名の付け方
どうやらWindows XPでは、すべて英数字のファイル名だと1行表示だが、2バイト文字や半角スペースなどが含まれているとファイル名が2行表示されるようだ。しかも、頭が英数字で始まり途中から2バイト文字が入っていると、2行目は2バイト文字から表示されるという仕掛けになっている。
ほー。それは知らなかった。
= リアルなチューリングマシンを作りたくなってしまった。

夏のプロシンでなにか発表しろといわれているので、 たぶんそこでこの発言の真意が明らかになります(ぉ)


= Haskellは封印しよう。 とりあえず「ふつうのHaskell」を見えないところにしまった。 あとモジュールの宣言の仕方はわかったけど、 そのモジュールをどうすれば他のコードからインポートできるのかがよくわからなかった。 とりあえずそれらしきフォルダにほりこもうか と思ったら、標準ライブラリは*.hiとかいうバイナリになっていた。

それから、自分で作ったRealっていう型に変換するために i2r :: Integer -> Realと q2r :: Rational -> Realを作り、 名前を使い分けるのが面倒なので下のようにしたら、 Rationalの所だけエラー。type Rational = Ratio Integerなのが関係しているのか? よくわからない。

class Realizable a where
  toReal :: a -> Real

instance Realizable Integer where
  toReal = i2r

instance Realizable Real where
  toReal = id

instance Realizable Rational where
  toReal = q2r
    Illegal instance declaration for `Realizable Rational'
        (The instance type must be of form (T a b c)
         where T is not a synonym, and a,b,c are distinct type variables)
    In the instance declaration for `Realizable Rational'

2007年03月16日

HaskellでKEMURIソルバーα0.2

HaskellでKEMURIソルバーができたけど、 「1つのPUSHで要求されたデータを作る」という条件が付いている。 まだ最小のコードを出力するとは限らない。 あと、1文字決定するのに11秒くらいかかる。 あ、「g」とかだと、メモリを1ギガ以上食ってものすごく時間がかかりそう。 ダメだなぁ、まだ枝刈りが必要だ。

__ 0.2にバージョンアップ。 0.1では「ROT ROTの後にはROTをおかない、DUPのあとにはDUPをおかない」というルールを入れていたのだけど、これでは「ROT DUP ROT DUP ...」でどんどん無駄に長いスタックを作れてしまう。そこで 「ROT ROTの後にはDUPをおかない、DUP ROTの後にはDUPをおかない、 DUP ROTの後にはROTをおかない」というルールを追加した。 厳密には「目的の文字列を出力するための最小の命令列にはこれらの命令列が含まれていない」ということを証明しないといけない。

でもとりあえずgも出力されるようになった。

(H): `^^^^^^^^^^'^"^^
(o): `^^^^''^"^^^^^^^^
(g): `^^^^^^'^''^"^^^^^
(J): `^^^^'^'^'^'^"^^^^^
Hより2ステップ長い。この2ステップがバージョン0.1では致命的だったのだ。

僕が以前手で書いたJをスタックに積むコードは

`"^^"^^^^"^^"^^^^^'"^^"^^'"^^"^^"'^"^^
なので、このソルバが出した
`^^^^'^'^'^'^"^^^^^
という解は約半分の長さ。

__ ダメだ。「u」の計算が終わらない。 まだまだだ。 アドホックな枝刈りでは解決できない。 冷静に考えてみよう。

スタックにn個積んである状態から、スタックに1個しかないじょうたいに行く過程では、 かならずn-1個の状態を通る。積まれた数が減る命令がXORだけだから。 というわけでn個からn-1個に変化する過程に注目しよう。

言い忘れたけども今回はNOTは使わないことにする。 証明していないけどもなくても構わないと思うので。

そうすると、ROTとDUPとXORの組み合わせで何ができるか、という話になる。 ROTで上3つを並び替えるのが一番深くまで触る命令だから、 スタックのそれより深い部分は無視していい。 つまりa b c -> ... -> x y。

ROTとXORとDUPの組み合わせでできる命令列のうち、 長さ3のスタック[1, 2, 3]を与えて実行すると スタックの長さが2になるような命令列を抽出(take 10)

^: Just [3,4]
'^: Just [6,1]
"^^: Just [2,4]
''^: Just [5,2]
"^'^: Just [6,0]
"'^^: Just [2,4]
'"^^: Just [4,1]
'''^: Just [3,4]
"^"^^: Just [2,4]
"^''^: Just [4,2]
見ての通り、ROT ROT ROT XOR は XOR と同じ結果になる。自明。 他にも DUP XOR XOR は DUP ROT XOR XORと同じ結果。

重複するものを取り除く。

^: Just [3,4]
'^: Just [6,1]
"^^: Just [2,4]
''^: Just [5,2]
"^'^: Just [6,0]
'"^^: Just [4,1]
"^''^: Just [4,2]
これが正しい道筋リスト。 ここで、1と2と4のXORで作ることのできる数は 0~7の8通りなので、 「スタックの長さが2になったときのスタックの中身」 は64通り。 重複したものを取り除いた後でtake 64する。

重複するものを取り除くところで下のようなことをしていたので無限ループに突入(苦笑)

uniq = foldl uniqAdd []

uniqAdd xs x = 
  if not(any (== (stack x)) (map stack xs)) then
    (x:xs)
  else
    xs
まぁ、十分な長さでtakeすることで、64本の「正しい道筋」リストが完成。 巻末に掲載。
= ソルバ0.2が作ったコードを見て思ったのだけど、 まず最初にXORを連打して捨てるべきなんだな。 探索の時も、まずPUSHで積んだ後、 XOR連打でスタックの長さが1になるまで縮めて、 ゴールかどうかを判定。 次にXOR連打で長さ2まで縮めて、下の3通りの「正しい方法」で1に縮めて ゴールかどうかの判定。
"^^: Just [2]
"'^"^^: Just [1]
"''"^^^: Just [0]

次にXOR連打で長さ3まで縮めてから、63通りの「正しい方法」で2に縮めて、 そこから3通りの正しい方法で1に縮めて判定。 …というような探索をすればいい気がする。解が見つかったら長さを枝かりに使う。

重要なのは「探索するごとにスタックの長さが1ずつ短くなる」ということ。 探索空間が有限になったので深さ優先で探索できる。 今度はそれを実装することにしよう。

ここまでやってもまだ最短ではないんだよなぁ。 1文字ずつ生成しているから。 例えば"d!"と表示するのに"d"と"!"を別々に作るより、 "Hello, world!"の最後の2文字を使って一度に2つ作る方が短いコードになるはず。


=

-- Kemuri ソルバ
import Data.Char
import Data.Bits

-- main = print $ start_kemuri "`|"

-- main = print $ showCode solve

-- main = print $ take 10 (bfs visit start)

-- main = print $ isGoal (Situation "" (km_xor (km_xor (km_dup (stack start)))))
-- main = putStr.show $ solve "H"

-- main = do input <- getContents
--          putStr (unlines (map format (map (:[]) input)))

main = putStr.format $ "g"

format goal =
  "(" ++ goal ++ "): " ++ (show (solve goal))

solve goal = (filter (isGoal goal) (bfs visit start)) !! 0

isGoal _ (Situation _ Nothing) = False
isGoal goal (Situation _ (Just x)) =
  x == map ord goal

showCode (Situation code _) = reverse code

bfs :: (a -> [a]) -> a -> [a]
bfs f = bfs' . (:[])
  where bfs' [] = []
        bfs' xs = xs ++ bfs' (xs >>= f)

visit :: Situation -> [Situation]
visit (Situation code Nothing) = []
visit (Situation code stack)
  = [Situation ('^':code) (km_xor stack)]
     ++ add_rot code stack ++ add_dup code stack

add_dup code stack@(Just xs)
  = if length xs < 15 then
      if head code == '"' then []
      else if take 2 code == "'\"" then []
      else if take 3 code == "''\"" then []
      else [Situation ('"':code) (km_dup stack)]
    else
      []

add_rot code stack
  = if take 2 code == "''" then
      []
    else if take 2 code == "\"'" then
      []
    else
      [Situation ('\'':code) (km_rot stack)]


data Situation =
  Situation {doneCode::String, stack::Stack}

instance Show Situation where
  show x = reverse $ doneCode x

start = Situation "`" (km_push (Just []))

operate_stack :: Stack -> Char -> Stack
operate_stack stack c = case c of
  '^' -> km_xor stack
  '~' -> km_not stack
  '\'' -> km_rot stack
  '"' -> km_dup stack
  '`' -> km_push stack
  _ -> stack

type KemuriResult = Maybe String

kemuri :: Stack -> String -> KemuriResult
kemuri stack (c:code)=
  case c of
    '|' -> if stack == Nothing then
              Nothing
           else
              add (km_mkstr stack) (start_kemuri code)
                where add (Just x) (Just y) = Just (x ++ y)
                
    c   -> kemuri (operate_stack stack c) code

kemuri Nothing _ = Nothing
kemuri _ []= Just ""

start_kemuri :: String -> KemuriResult
start_kemuri code = kemuri (Just []) code

type Stack = Maybe [Int]

km_xor :: Stack -> Stack
km_xor (Just (x:(y:rest))) = Just ((xor x y):rest)
km_xor x = Nothing

km_not :: Stack -> Stack
km_not (Just (x:rest)) = Just ((complement x):rest)

km_rot :: Stack -> Stack
km_rot (Just (x:(y:(z:rest))))  = Just (y:z:x:rest)
km_rot x  = Nothing

km_dup :: Stack -> Stack
km_dup (Just (x:rest)) = Just (x:x:rest)

km_push :: Stack -> Stack
km_push (Just xs) = Just (map ord "Hello, world!" ++ xs)

km_mkstr :: Stack -> KemuriResult
km_mkstr (Just xs) = Just (map chr xs)
km_mkstr Nothing = Nothing

= スタック[1, 2, 4]から長さ2のスタックへの「正しい道筋」リスト。
^: Just [3,4]
'^: Just [6,1]
"^^: Just [2,4]
''^: Just [5,2]
"^'^: Just [6,0]
'"^^: Just [4,1]
"^''^: Just [4,2]
"'^'^: Just [5,3]
'"^'^: Just [5,0]
''"^^: Just [1,2]
"^'"^^: Just [4,0]
"'^"^^: Just [1,4]
"'^''^: Just [7,1]
'"'^'^: Just [3,6]
''"^'^: Just [3,0]
"^''"^^: Just [0,2]
""^'^'^: Just [4,3]
"''"^^^: Just [0,4]
'"^'"^^: Just [1,0]
'"'^"^^: Just [2,1]
'"'^''^: Just [7,2]
''"'^'^: Just [6,5]
"^'"'^'^: Just [2,6]
"^''"^'^: Just [2,0]
""^'^''^: Just [7,0]
"'^''"^^: Just [3,1]
"''"^^'^: Just [5,1]
'""^'^'^: Just [1,6]
'"''"^^^: Just [0,1]
''"'^''^: Just [7,4]
"^'"^'"^^: Just [0,0]
"^'"'^''^: Just [6,2]
"^''"'^'^: Just [6,4]
"'^"'^''^: Just [6,3]
"'^'"'^'^: Just [2,5]
'"^'"'^'^: Just [4,5]
'"''"^^'^: Just [3,2]
"^'""^'^'^: Just [0,6]
""^'^"'^'^: Just [7,3]
"'^'"'^"^^: Just [1,3]
"'^''"'^'^: Just [5,7]
'"^'"'^''^: Just [5,4]
'"'^"'^''^: Just [5,6]
"^'"^'"'^'^: Just [4,4]
"^'"''"^^'^: Just [2,2]
"'^"^'"'^'^: Just [1,5]
"'^"'^''"^^: Just [2,3]
"'^'""^'^'^: Just [3,5]
"'^'"''"^^^: Just [0,3]
"''"^^''"^^: Just [1,1]
'"^'""^'^'^: Just [0,5]
'""^'^"'^'^: Just [7,6]
'"'^''"'^'^: Just [3,7]
"^"'^''"'^'^: Just [4,6]
""^'^''"'^'^: Just [4,7]
"'^"'^'"'^'^: Just [1,7]
''""^'^"'^'^: Just [7,5]
''"'^''"'^'^: Just [6,7]
"^'""^'^"'^'^: Just [6,6]
""^'^"'^''"^^: Just [3,3]
"''"^^''"'^'^: Just [5,5]
'"'^"'^'"'^'^: Just [2,7]
""^'^"'^'"'^'^: Just [0,7]
""^'^"'^''"'^'^: Just [7,7]
スタック[1, 2]から長さ1のスタックへの「正しい道筋」リスト。
^: Just [3]
"^^: Just [2]
"'^"^^: Just [1]
"''"^^^: Just [0]

30歳になりました日記

予算の消化をしないと年度末までの書類がそもそも書けない。

僕は予算の消化が大嫌い。

相談した人が2桁多い額を消化していてびっくり。 あ、でも年度末に残ったお金と年間で消費したお金を比較するのはおかしいか。

とりあえず見積もり。 微妙に予算が残ってしまったら、例の付箋を買おう。 例の付箋ってなんだっけ。 「西尾 泰和 付箋 サイズ」で検索。

ST-MN3という3Mの付箋を買ってきました。決め手はサイズで、100mm×69mmと普通のメモ用付箋より微妙に狭く、長いものです。これ実はA4 用紙を8つ折りにしたスペース105mm×74mm(つまりA7)にちょうどはみ出さずに収まるサイズなので、A4の四つ折りサイズである超整理手帳の1 ページにちょうど2枚ぴったり貼ることができるわけなのです。
そうなのです。 最初付箋に厚紙のカバーが付いているのは邪魔に感じたのですけど、 カバンに入れておいてもめくれてぐちゃぐちゃにならないし、 さっと取り出したい分はあらかじめ手帳に張っておけばいいだけ。 超整理手帳との相性は抜群。

ただし超整理手帳自体は全然使っていない(ぇー)

スケジュールの密度の問題だと思う。 いろいろなスケジュールの管理方法とかがあるけど、 管理すべきデータの量によって適切な管理の方法が変わるのは当たり前。 僕のケースでは付箋で十分。

ただ、済んだ作業の記録は残らずにどんどん廃棄されている。 それでいいような気もするけど。 あとから「あー、あれなんだっけー」となるような情報は取っておく方がいいんだろうなぁ。 でも、それを紙の形で取っておくと検索性が低いから、 必要な情報だけhowmに転記とかがいいのかもなぁ。

公開しても問題ない情報なら上のように日記に書いておいてGoogleで検索するし。

そして必要を感じて検索した情報はこうやって転載することで次の時により見つけやすくする。


= うはー! 体年齢が30歳の誕生日を迎えました!orz

1ヶ月前は27と28を行き来するくらいだったのに、 数日前に29になり、今日はとうとう30歳に。

チョコパイがいけないんだ。


= Haskellしたくなるのを我慢。 Jython本の原稿を書かなきゃ。
= 普段、文字列を音として認識する習慣がないので、 原稿を読んでみると意外な所に時間が取られる。 Pythonの作者Guido van Rossumってどう発音するんだ。 「ぐいどー」と呼んでいる人が多いけど、 本人のページ( Guido's Personal Home Page )には「アメリカ人はイタリア風の発音で呼ぶことが多いけどね」と書いてあり、 Wiktionaryによればイタリア風の発音こそ「ぐぅぃーどー」だ。 Guido - Wiktionary

発音は「Scottish "loch"」のchに似ている、って言われてもね。 IPAの発音記号で言うと「x」。もしかしてTeXのXか。

オランダ語 - WikipediaによるとGという文字の発音は[x]か[?](yみたいなの)で、 両方とも軟口蓋摩擦音。有声軟口蓋摩擦音 - Wikipedia

もろもろの情報から考えると、やっぱりTeXのXの発音で、仮名表記するならハ行。

そしてつづく「ui」の発音は、発音記号で書くと[oey]。読めない…。 まぁ「アイ」のような「エイ」のような「オイ」のような音らしい。

まぁ、あえて仮名表記すれば「ホイド=ファン=ロスム」かなぁ。 名前のほとんどの字が「日本語や英語で表現しにくい発音」なので かなり無意味だけど。 「ヴァン」か「ファン」か、とか、「ロスム」か「ロシュム」か、 という議論はほぼ無意味。どちらも正確ではない。

と、こんなくだらないことを調べて時間を費やしてしまう。 そんなことより原稿を…。 うーん。


= 「言語融合の時代」 を整理して書き直し。 第三の時代は単なる言語融合の時代になった。 前回の文章で言語融合とセットにした「コンポーネント化の流れ」は 設計思想の変化なのだ。混ざっているとわかりにくいと思ったので削った。 プレゼンの時も削ったしね。

あえていうならば、 機械語の時代にジャンプと命令の羅列だったものが、 第一の時代にwhileやifなどの構造と関数になり、 第二の時代にクラスや継承になった、と。 でも継承は答えではないことに気がついた。 だからSWTは継承を禁止した。 だからDIが流行った。 DIコンテナって「XMLで記述された『部品をどう組み合わせるか』というコード」を読んで、 実行するインタプリタじゃん。 これも実は「複数の言語でプログラミングをする」の一礼じゃん。 ということなのだ。

Java風にいえばインターフェイスだが、 ようするにあるオブジェクトXがオブジェクトYと関係を持つときに、 オブジェクトYが「なんらかの条件」を満たしていることを保証してほしい、ということ。 ある種の契約なんだ。 これからはある種の言語でコンポーネントを作り、 別の種類の言語でコンポーネント同士の関係、契約、などなどを記述する形になるだろう。 そういう方向の進化を考えた場合、 現状のJavaも現状のPythonも多少力不足だと思う。 Javaでコンポーネントを作っても、 「XがYを呼び出す」なんて処理はJavaの中で完結してしまっていて、Pythonの側でフックしにくい。 もちろんできなくはないが。 そうではなくて、ちょこっと宣言を書くだけでその呼び出しの処理の前に何かの関数を挟んだり、 引数をそのまま渡さずに指定した関数を通して変化させてから渡したり、といった処理ができるような、 そんな言語が現れるだろうと思う。あと5~10年くらいで。 で、その言語がデファクトスタンダードになるまで10年かかって、 その頃には言語を問わないCPANのような物ができていて、 C#やJavaで書かれたコンポーネントがMaven的な方法で自動的にダウンロードできて、 あとはそのコンポーネントのつなぎ合わせを書くだけ。


= やばい、疲れが出てきたのに、 ローズマリーのアロマが強すぎて脳が止まらない。 クールダウンしないと。
= クールダウンした。 西尾泰和のブログ: HaskellによるKEMURIインタプリタ

HaskellによるKEMURIインタプリタ

HaskellでKEMURIのインタプリタを書いてみた。 KEMURIとは - はてなダイアリー

超絶短くてびっくり。西尾泰和のブログ: KEMURIのPythonで書かれたのの約半分の行数。 実装時間の半分以上はビット演算と文字から文字コードに変換する方法を調べるのに費やされた。kemuri関数の中身は割とくだらないことをしているので、たぶんもっと短くスマートに書く方法があるだろうと思う。

-- Kemuri インタプリタ
import Data.Char
import Data.Bits

main = getContents >>= putStr.(\code -> kemuri code [])

kemuri :: String -> [Int] -> String
kemuri ('|':code) stack = km_mkstr stack ++ kemuri code []
kemuri ('^':code) stack = kemuri code $ km_xor stack
kemuri ('~':code) stack = kemuri code $ km_not stack
kemuri ('\'':code) stack = kemuri code $ km_rot stack
kemuri ('"':code) stack = kemuri code $ km_dup stack
kemuri ('`':code) stack = kemuri code $ km_push stack
kemuri (c:code) stack = kemuri code stack
kemuri [] _ = ""

km_xor (x:(y:rest)) = (xor x y):rest
km_not (x:rest) = ((complement x):rest)
km_rot (x:(y:(z:rest)))  = (y:z:x:rest)
km_dup (x:rest) = (x:x:rest)
km_push xs = map ord "Hello, world!" ++ xs
km_mkstr xs = map chr xs

__ KEMURIソルバーを作りたかったのだけど、難しかった。幅優先探索と枝刈りをどう実装したらいいのか。 「探索待ち行列に追加」なんてのはリストの破壊的操作ができないから無理だし。リストを順に受け渡していくのか?でも高速な(x:xs)での結合では頭に入れて頭から出してしまうからキューにならないし、 素直にキューにしたらリストの操作だけでかなり重たそう…。


__ Programming:玉手箱:その他。おおー、なんかすごく短い幅優先探索のコードがあった。


__ 捨てるのがもったいないので転載。^'"の3文字からなる文字列を順に生成するリスト。

all_code = foldr1 (++) (iterate f (map (: []) "^'\""))
f xs = [y:x | x <- xs, y <- "^'\""]

2007年03月14日

Haskell日記

整数と浮動小数点数をそのまま演算できないのはまだいいとして。 IntをFloatに変換する関数がfromIntegralなのはどうしたものかと。
= これはstack overflow。
main = print $ foldl1 (*) [0..1000000]
これもstack overflow。
main = print $ foldl1 mul [0..1000000]

mul 0 _ = 0
mul _ 0 = 0
mul x y = x * y
悲しい。

あ、foldr1に変えたら動いた。

でも

main = print $ foldr1 (*) [0..1000000]
はやっぱりダメ。

ああ、そうか、外側から評価されるからfoldlじゃなくてfoldrである必要があったのか。 「0 * (1 * (2 * (...)))」だもんな。 今まで使ってきた言語はかっこの奥から評価されるけど、Haskellは逆。


=
inc :: Int -> Int
inc n = n + 1

main = print $ inc inc 1
こうすると、((inc inc) 1)と判断されるので 「incの引数はIntなのに、Int -> Intの関数が来ているぞ」 というエラーになる。

かっこをつけて結合順序を明示してやると正しく3と表示される。

main = print $ inc (inc 1)
この場合は$を使ってこう書ける。
main = print $ inc $ inc 1
しかしかっこが行末まで行かない場合は、$を使えない。
main = print $ (inc (inc 1)) * 2   -- 6
main = print $ inc $ inc 1 * 2     -- 5
関数合成を使って二つのincを合成してしまえばいいのでは、と思った。 しかし、関数合成のドットよりも、関数適用のスペースの方が強かった。
main = print $ inc.inc 1 * 2     -- error
-- (inc . (inc 1)) * 2
スペースが一番強い演算子ってのにはなかなか慣れられないなぁ。
= Haskellは遅延評価をしてくれるけども、 頭のいい遅延評価をしてくれるとは限らない。
main = print $ foldr1 min $ map length [[3..100], [2..10], [1..]]
これは[2..10]の長さが9なので、 [1..]の長さを調べていって9以上であることがわかった時点でbreakできるのだけど、 Haskellはそんなこと考えずに長さを求めようとしてしまうので無限ループになる。 minの引数をパターンマッチする際に評価してしまうから。
= Haskell飽きてきた。 何か簡単なものを作って終わりにしよう。
=
main = print $ foldr1 min $ map length [[3..100], [2..10], [1..]]
はlengthのパターンマッチで評価が起きてしまうので、 無限ループに陥る。 それを無限ループに陥らせない方法。

まずIntの代わりにMyIntを用意。特定の値だけではなく、 「特定の値以上」という状態を取れるようにした。

次にIntを返すlengthの代わりに、MyIntを返すMyLengthを用意。 空リストの長さは0だと返すが、 それ以外は「1よりは長いみたい」とだけ返して細かいことを調べない。

で、その「あいまいな」MyIntを1歩具体化する関数progressを用意。

最後に、それらを使って、値をなるべく確定させないまま最小値を求めるmyMinを定義。

main = print $ myIntToInt $ foldr1 myMin $ map myLength [[3..100], [2..10], [1..]]

data MyInt = MoreThan {val :: Int, rest :: MyInt} | Equal Int

myLength :: [a] -> MyInt
myLength [] = Equal 0
myLength (x:xs) = MoreThan 1 (myLength xs)

progress :: MyInt -> MyInt
progress (Equal x) = (Equal x)
progress (MoreThan x (Equal y)) = (Equal (x + y))
progress (MoreThan x (MoreThan y z)) = (MoreThan (x + y) z)

myMin :: MyInt -> MyInt -> MyInt
myMin (Equal a) (Equal b) = Equal $ min a b

myMin x (Equal b)
  = if val x > b
      then (Equal b)
      else myMin (progress x) (Equal b)

myMin (Equal b) x
  = if val x > b
      then (Equal b)
      else myMin (progress x) (Equal b)

myMin x y
  = if val x < val y
      then myMin (progress x) y
      else myMin x (progress y)

myIntToInt (Equal a) = a
(Equal x)と(MoreThan val rest)みたいな、違う形のものを同じ型で呼べるところがちょっと面白い。
= なんか腰がすごく痛い。 なぜ。
= The monad laws
最初の規則は return が >>= に関して左単位元になっていることを要請しています。二番目の規則は return が >>= に関して右単位元になっていることを要請しています。
これはあからさまにおかしい。 「>>=」は右と左で取る値の型が違うので、同じ物が左単位元かつ右単位元になるのはおかしい。

returnはなんだろう。 return :: a -> m a と >>= :: m a -> (a -> m b) -> m b を合成して一つの関数にすると、 a -> (a -> m b) -> m bになる。 なんかapplyっぽい型。 「(return x) >>= f == f x」を満たすということは 「見かけがapplyっぽいだけじゃなくて、 挙動も単なるapplyですよ」ってこと。

「出口はない」 は厳密には「出口は必須ではない」とか「出口があるとは限らない」だよなぁ。 詳細をエクスポートしなければ、取り出す手段がなくなってしまうというだけだから。 Javaのprivateみたいに隠すことができます、ということでしかない。

m >>= (\x -> mzero) == mzero
これは、満たさなければいけないルールではなくて、 単にこういう挙動を示しますよ、ってことかな。 >>=が単なる「中途半端なapply」である以上、 「なにを入れてもmzeroを返す関数」を与えたら、 当然mzeroが返ってくるように思う。
mzero を 0 に、mplus を + に、そして、 >>= を × という算術演算にそれぞれ対応させれば、 mzero および mplus の法則を覚えるのは簡単です。
いや、算術演算の×は両側のオペランドの型が同じでしょう…。 ああ、そうか、 >>= と (\x -> \_ -> x) という関数を合成したものを仮にtimesと呼ぶことにすれば、 times :: m a -> m a -> m a になって掛け算と同じになるのか。(mplusの左右が交換できることから a == bなので。) そうすると「m >>= (\x -> mzero) == mzero」は「m times mzero == mzero」になる。 でも1番目の式はうまく表現できないか…。

やっぱり、>>= を ×にたとえるのは根本的に間違っている気がする。 だって >>= ってモナドを1つとって(関数も取って)1つ返す関数だもん。 mzeroを2次元のベクトル(0, 0)に、mplusをベクトルの足し算に、 そして >>= を 「実数kを取って、ベクトルをk倍する関数」にたとえる。

mzero >>= f == mzero -- (0, 0)ベクトルは何倍しても(0, 0)
m >>= (\x -> mzero) == mzero -- どんなベクトルも0倍すれば(0, 0)

= HaskellのclassはJavaのinterfaceで、 instance Monad Maybeってのはclass Maybe implements Monadだと思った。

うむ。 「instance Monad Maybe」をJavaやPythonの「インスタンス」の意味で 「MaybeはMonadのインスタンス」と考えるとつまずく。 それらの言語ではインスタンスはクラスを1つしか持たないけど、 HaskellではShowとOrdとか複数のクラスのインスタンスになれるから。


= 昨日の続きで「パターンマッチでは評価しきらない正の整数型」を洗練させてみた。
main = print $ min (myLength[3..100]) (myLength[1..] * fromInteger(10))
minとか+とか*が使えるようになった。 これを使うと、枝刈りが楽になりそうな気がするのだ。 西尾泰和のブログ: Python Developer's camp 日記 でtypoチェッカーを作ったときに、 レーベンシュタイン距離 - Wikipedia の計算が遅延評価だと楽だなぁと思ったのだった。 n×mの配列を隅から順に塗りつぶしていくいかにもC言語的なアルゴリズムでは、 「最終的なスコアがx以上になるなら正確な値を求めなくていい」 と言われても枝刈りがしにくい。

でも、結局今日一日Haskellで遊んでしまった。 明日からは原稿書きに復帰しないとなぁ。 書類も書かないといけないし、予算も消化しないといけないし、 引っ越しもしないといけない。

2007年03月13日

Tomcatハック日記2 JSPの章

JSPに初挑戦。 見よう見まねでとりあえずJythonが動くようにしてみた。
<%@ page
    contentType="text/html; charset=Shift_JIS"
    session = "false"
    import = "org.python.util.PythonInterpreter"
%>
<html>
<body>
<pre>
<%
  PythonInterpreter pyi = new PythonInterpreter();
  String code = request.getParameter("code");
  pyi.set("out", out);
  pyi.exec("import sys; old_out = sys.stdout; sys.stdout = out");
  if(code == null){
    code = "";
  }
  pyi.exec(code);
  pyi.exec("sys.stdout = old_out");
%>
</pre>
<form method="post" action="test.jsp">
  <textarea name="code" cols=80 rows=10><%= code %></textarea><br>
  <input type="submit">
</form>
</body>
</html>
テキストエリアに「print "hoge" * 3」とか書いてsubmitボタンを押すと、 ちゃんと「hogehogehoge」と表示される。 でもこれだとPythonインタプリタが毎回死んでしまう。 どうしたらいいのかな。

とりあえずsession.setAttributeして使い回すようにしてみた。 セッションが続いている間は同じインタプリタを使うようにした。 import osしたら、os.listdirでローカルのファイル一覧が見える。 特にセキュリティ上の制約とかはないみたいだ。

「print session.getValueNames()」で 「array(['pyi', 'hoge'], java.lang.String)」と表示された。 「session.setAttribute("hoge", 2)」で問題なく書き換えられた。

とりあえずsessionの中身を自由に書き換えられるようにはなった。

アプリケーションスコープの変数を使えば 他のセッションとPythonインタプリタを共有できそうだ。 Firefoxの画面で「x = 1」を実行してから、IEを起動して「print x」とやったら、 無事「1」と表示された。

あとは何ができるとうれしいんだろう。 見かけを対話型インタプリタに近づけるのは、技術的には難しくないと思うしな。 チャット風に。

<%@ page
    contentType="text/html; charset=Shift_JIS"
    import = "org.python.util.PythonInterpreter"
%>
<html>
<body>
<textarea cols=80 rows=10>
<%
  PythonInterpreter pyi = (PythonInterpreter)application.getAttribute("pyi");
  if(pyi == null){
    pyi = new PythonInterpreter();
    application.setAttribute("pyi", pyi);
  }
  String code = request.getParameter("code");
  pyi.set("session", session);
  pyi.set("out", out);
  pyi.exec("import sys; old_out = sys.stdout; sys.stdout = out");
  if(code == null){
    code = "";
  }
  pyi.exec(code);
  pyi.exec("sys.stdout = old_out");
%>
</textarea>
<form method="post" action="test.jsp">
  <textarea name="code" cols=80 rows=10><%= code %></textarea><br>
  <input type="submit">
</form>
</body>
</html>

= 雨蛙散乱前線。
= JythonインタプリタからJyConsoleを起動する。 昨日JythonインタプリタからTomcatを起動したのと同じ方法で起動まではうまく行く。 でも、Jythonインタプリタ側の入出力が動かなくなる。

よく考えたら普通にJavaプログラムでJyConsoleを立ち上げた上で、 そのJyConsoleの持っているPythonインタプリタに、 そのPythonインタプリタへの参照をつっこんでやればいい。 自分自身を動的に書き換えられるインタプリタになる。

package org.nishiohirokazu.jythonbook.test;

import javax.swing.JFrame;

import com.artenum.jyconsole.JyConsole;
import com.artenum.jyconsole.python.JInteractiveInterpreter;

public class Ouroboros {
	public static void main(String[] args) {
		System.setProperty("python.security.respectJavaAccessibility", "false");
		JyConsole jyc = new JyConsole();
		JInteractiveInterpreter pyi = jyc.getPythonInterpreter();
		pyi.set("pyi", pyi);
		
		JFrame f = new JFrame();
		f.setSize(500, 300);
		f.add(jyc);
		f.setVisible(true);
	}
}

= 今日は研究室の今年度最後の意見交換会。 ある種の忘年会。忘年度会。

そんなわけでまとまった執筆はできないと踏んでいたので色々試してみた↑

あととりあえずGHC(Haskell)をインストールしてみた。 missingPyを試したい。

ghci(対話的インタプリタ)で関数が定義できないって、ひどい。

HelloWorldできた。 mainという変数の値はアクションというものらしい。 ふむふむ。 たぶん純粋な関数のことだけを関数と呼んで、 副作用のある関数はアクションと呼ぶんだろう。

main = do x <- "Hello. world"
          putStrLn x
怒られた。
main = putStrLn x where x = "Hello. world"
こうか。
main = let x = "Hello. world"
       in putStrLn x
これもOK。

関数適用は f arg1 arg2 arg3で Java風にいうとf(arg1, arg2, arg3)になるわけだけど、 これって部分適用があるから f(arg1)(arg2)(arg3)なんだよね?

Lispと比べて括弧が少ないけど、 その代わりに$があるよ!

階乗。

main = print $ facto 5

facto :: Int -> Int
facto 1 = 1
facto n = n * facto (n - 1)
パターンマッチで関数を定義するところがPrologっぽくて面白い。 あと、最初「main = print facto 5」と書いて怒られた。 factoにprintを適用してしまうんだな、きっと。 関数適用が左結合性ということ? 「facto (n - 1)」も最初 「facto n - 1」と書いて、スタックオーバーフロー。 「facto(n) - 1」と認識されたんだろう。

LispやSchemeと違って括弧が省略できて楽だけど、 その分、どこがどう結合するのかは意識する必要がありそう。

「facto $ n - 1」にすると怒られる。 たぶん n を関数だと思ったんだろう。 「facto & - n 1」にしても怒られる。 たぶん - は関数ではないんだろう。

あ、違う。 「facto $ n - 1」にすると怒られるのは 「(n * facto) $ (n - 1)」と解釈されて、 IntのnとInt->Intのfactoの掛け算が定義されていないからだ。

facto n = (\x -> n * x) $ facto $ n - 1

これならちゃんと動く。括弧なしで書こうと思ったんだけど、とっちゃうとダメ。

carがheadでcdrがtail。


=
main = print  $ minMap [3, 2, 5, 1]

minMap :: [Int] -> Int
minMap [x] = x
minMap (x:xs) = min x $ minMap xs
ふむふむ。
= 100までの素数。
main = print  $ filter isPrime [2..100]

isPrime :: Int -> Bool
isPrime x = not $ any (\n -> n == 0) $ map (mod x) [2..x-1]
簡単。「(\n -> n == 0)」はなんかいい書き方ないのかなあ。
= ガードを使ってみた。Collatzの数列。
main = print  $ collatzList 7

collatz :: Int -> Int
collatz x | mod x 2 == 0 = div x 2
          | otherwise    = x * 3 + 1

collatzList :: Int -> [Int]
collatzList 1 = [1]
collatzList n = n: (collatzList $ collatz n)
「n: $ collatzList $ collatz n」ってやったら怒られた。
= 三段論法(笑)
main = print  $ die "socrates"

die x | human x = True
      | otherwise = "unknown"

human "socrates" = True

= おお、演算子をかっこで囲うと前置にできるんだそうな。 100までの素数を求めるコードはこうなる。
main = print  $ filter isPrime [2..100]

isPrime :: Int -> Bool
isPrime x = all ((<) 0) $ map (mod x) [2..x-1]
たぶん関数の合成を使うともっとスマートに書けるんだろう。
=
main = print $ filter (\x -> all (((<) 0).(mod x)) [2..x-1]) [2..100]
あんまりスマートではない。
= 二項演算子に部分適用を使う場合、(0 <)とか(< 0)とか書けるそうな。
main = print $ filter (\x -> all ((0 <).(mod x)) [2..x-1]) [2..100]
!=は/=らしい。
= Haskellでは関数適用が一番優先順位が高い。ひどい。 一般的な言語ではf(arg1, arg2, arg3)と関数を呼ぶ際に、 fとarg1の間のかっこや、arg1とarg2の間のカンマは最も優先度の低い演算子の役割をする。 でもHaskellの場合はf arg1 arg2 arg3の間の空白文字が一番優先度の高い演算子。見えないくせに。

というわけで(mod x)の周りのかっこはとりのぞける。

main = print $ filter (\x -> all ((0 <).mod x) [2..x-1]) [2..100]

= そんなわけで「ふつうのHaskell」を220ページまで読んだわけだけど、 いよいよ型と型クラス。どきどき。

モナド。どきどき。

モナドって、例えばリストに対して追加を行う関数appendは、適用する順番が大事だから、

append (append (append [] 1) 2) 3
というように書かないといけないところを、
(bind (bind (return 1) append 2) append 3)
と書けるようにbindとreturnを定義して、 bindを二項演算子に変えて
(((return 1) >>= append 2) >>= append 3)
余計なかっこを取り除いて
return 1 >>= append 2 >>= append 3
とした、というだけ?
= 自分でモナドを定義してみようとしたのだけど
    No instance for (Show (m t))
      arising from use of `print' at test.hs:1:7-11
    Possible fix: add an instance declaration for (Show (m t))
    In the first argument of `($)', namely `print'
    In the expression: print $ (return 1)
    In the definition of `main': main = print $ (return 1)
printがないって怒られる。 もう寝よう。
=
instance Show MyMonad where
  show (MyMonad x) = show(x)
こんどはkind mis-matchといわれるようになった。

2007年03月12日

タスクバーで目的のショートカットを選ぶまでの時間を短縮

ショートカットをツリー状に編成することで、 頭の決まり字を打つだけでショートカットが選べるようになります。

screen.png

あらかじめ、適当なフォルダにショートカットを集めておきます。 この時に日本語名のショートカットは適当なアルファベットの名前にしておくといいでしょう。

次に下のスクリプトを実行します。 Pythonをインストールしていない人はインストールしてください。 またinDirとoutDirの所を自分の環境に合わせて書き換えます。 inDirがショートカットを集めたフォルダ、 outDirがショートカットをツリー状に出力するフォルダです。

実行すると、上の図のようにショートカットが編成されます。 inDirの中身はそのまま残るので、 更新したいときはinDirにショートカットを入れてスクリプトを実行するだけ。 inDirへのショートカットと、スクリプトへのショートカットを、 inDirに入れておくといいでしょう。

outDirが「,」(カンマ)というファイル名なのには理由があります。 筆者のマシンはThinkpadなのでWindowsキーがありません。 しかし右AltをWindowsキーに変えることができます。 カンマは右Altの左上にあるので、ホームポジションJに人差し指をおいたまま 少し右手を回転させると薬指がWinキー、中指がカンマになります。

# -*- coding: cp932 -*-
"""
shortcutTree.py ショートカットをツリー状に編成する
"""
#
# setting

inDir = r"C:\Home\shortcut"
outDir = r"C:\Documents and Settings\All Users\スタート メニュー\,"

# end setting
#

import os, shutil
join = os.path.join

if os.path.isdir(outDir):
    # すでに存在したら消す
    shutil.rmtree(outDir)

os.mkdir(outDir)

def makeTree(nameList):
    result = {}
    for (name, origName) in nameList:
        c = name[0].lower()
        cdr = name[1:]
        if result.has_key(c):
            result[c].append((cdr, origName))
        else:
            result[c] = [(cdr, origName)]

    return result

def arrange(nameList, outDir):
    tree = makeTree(nameList)
    for c in tree:
        if len(tree[c]) == 1:
            (name, origName) = tree[c][0]
            name = c + name
            shutil.copy(
                join(inDir, origName),
                join(outDir, name))
        else:
            os.mkdir(join(outDir, c))
            arrange(tree[c], join(outDir, c))

arrange([(f, f) for f in os.listdir(inDir)], outDir)
print "ok."

Tomcatハック日記

昨日の続き。 結局URLClassLoaderでやるのは無謀そうだったので、 すなおにクラスパスとかを指定したのだった。

>>> import org
>>> org.apache.catalina.startup.Bootstrap
<jclass org.apache.catalina.startup.Bootstrap at 20696008>
>>> B = _
>>> B.main(["start"])
(略)
2007/03/12 12:51:13 org.apache.coyote.http11.Http11Protocol init
情報: Coyote HTTP/1.1を http-8080 で初期化します
(略)
2007/03/12 12:51:16 org.apache.catalina.startup.Catalina start
情報: Server startup in 3031 ms
無事JythonからTomcatが起動した。 でもブロックされてしまう。
>>> import thread
>>> import org.apache.catalina.startup.Bootstrap as B
>>> thread.start_new_thread(B.main, (["start"],))
(略)
あ、respectJavaAccessibility=falseにするのを忘れてた。
>>> B.daemon
org.apache.catalina.startup.Bootstrap@1d1e765
>>> B.catalinaDaemon
<reflected field private java.lang.Object org.apache.catalina.startup.Bootstrap.
catalinaDaemon at 11703650>
>>> B.daemon.stop()
2007/03/12 13:19:38 org.apache.coyote.http11.Http11Protocol pause
情報: Coyote HTTP/1.1を http-8080 で一時停止します
(略)
2007/03/12 13:19:39 org.apache.coyote.http11.Http11Protocol destroy
情報: Coyote HTTP/1.1を http-8080 で停止します
うーむ。一応JythonからTomcatを起動して、 そのデーモンのフィールドにアクセスすることはできたけど、 ここからどうやって「おお、それはすごい」というデモにつなげればいいかがよくわからないなぁ。
= 伝言ゲーム。 スラッシュドット ジャパン | 神経は電気ではなく音を使う?

いやはや。 どこからつっこんでいいかすらわからない。

On soliton propagation in biomembranes and nerves -- Heimburg and Jackson 102 (28): 9790 -- Proceedings of the National Academy of Sciences。 これが概要か。 どこをどう読んだら「神経は電気ではなく音を使う」という話が出てくるのかさっぱりわからない。 たくさん出てきているmeltという単語を全部まとめて無視しているのか?

そんなことより「melting transitions」が専門用語かどうか確かめようとしてググったら、 渡辺さんとこにヒットしたw

簡単に説明しようかと思ったけど、間違ったことを書くのは嫌なので調べていたら、 いつの間にか時間が…。そう、こうやって日記に「執筆力」を割いてしまうと 本の執筆が進まないんだった。というわけで半分くらい書いたけど削除。 ソリトンがエネルギーを伝えるからchain meltingが起きる、って理解で正しいでしょうか?

はっ。スルー力か。


= The py.test tool and library
2.12 継承を必要としません

テストクラスは Test で始まる名前で認識されます. unitest.py とは違い, テストランナーに見つけてもらうために, あるクラスを継承することは必要ではありません. さらに簡単なことに, アプリケーションクラスを継承したテストクラスを書くことが出来できます.

ああ、なるほど。 それは確かに便利そう。
= GROW ver.3 Flash Game Planet___EYEZMAZE をついついやってしまった。 とりあえず並んでいる順番においてみて、得られた情報から適当に並べてみると3回目で1つを残してmaxに。 なんだ、かんたんじゃん、と思ったらそこからさらに3回かかってしまった。 だってあれとあれがインタラクトするとは思わなかったんだもん。

この問題を自動生成できないかなぁ。 っていうかテキスト形式なら自動生成できるなぁ。 問題は「アイテム 1 が Level 3 に上がりました」 「アイテム 4がアイテム 5 とインタラクトしました」 という文字列が出力されるゲームがどれくらい面白いのかだ。

考える力を計るテスト問題にはなるなぁ。少なくとも。


=
>>> B.daemon.catalinaDaemon
StandardService[null]
>>> c = B.daemon.catalinaDaemon
>>> c.class
<jclass org.apache.catalina.startup.Catalina at 9048956>
>>> [m.name for m in c.class.methods]
['stopServer', 'stopServer', 'await', 'setCatalinaHome', 'setCatalinaBase', 'set
ParentClassLoader', 'setConfig', 'setConfigFile', 'getConfigFile', 'setUseShutdo
wnHook', 'getUseShutdownHook', 'setServer', 'main', 'load', 'load', 'start', 'de
stroy', 'stop', 'create', 'process', 'setAwait', 'setCatalinaHome', 'setCatalina
Base', 'getCatalinaHome', 'getCatalinaBase', 'addLifecycleListener', 'addConnect
or', 'setUseNaming', 'isUseNaming', 'isRedirectStreams', 'setRedirectStreams', '
getRealm', 'setRealm', 'isAwait', 'createConnector', 'createConnector', 'createC
onnector', 'createConnector', 'createEngine', 'createHost', 'createLoader', 'rem
oveContext', 'removeEngine', 'removeHost', 'addAuthenticator', 'findLifecycleLis
teners', 'removeLifecycleListener', 'createContext', 'addEngine', 'getInfo', 'po
stDeregister', 'postRegister', 'preDeregister', 'preRegister', 'getObjectName',
'removeConnector', 'setContainer', 'getContainerName', 'getServer', 'getConnecto
rNames', 'findConnectors', 'getName', 'toString', 'init', 'setName', 'initialize
', 'addPropertyChangeListener', 'removePropertyChangeListener', 'getContainer',
'getDomain', 'hashCode', 'getClass', 'wait', 'wait', 'wait', 'equals', 'notify',
 'notifyAll']
うーん。 やっぱり道は長そうだ。 走っているTomcatを止めずに一部のオブジェクトを書き換えたり差し替えたりすることは、 原理的にはこの方法でできるのだけど、実際にやるにはTomcatの中の仕組みを 理解する必要がある。 簡単にできそうだったらJython本にサンプルの一つとして載せようかと思ったのだけど、 なかなかそうも行かなさそうだ。

十分時間があれば別なんだけども、 Tomcat本を書くわけではないので、 今からTomcatの中身を勉強するよりは現状でわかっていることだけで本を仕上げた方がいいだろう。

試してみたい人のための情報。 Jython2.1をインストールして、jython.batをコピーし、 最後の行を下のように書き換える。もちろん自分がJREやTomcatを入れた場所に応じてパスを変更すること。

"C:\Program Files\Java\jre1.5.0_10\bin\java.exe" "-Dpython.home=c:\jython-2.1" -classpath "c:\jython-2.1\jython.jar;C:\apache-tomcat-6.0.10\bin\bootstrap.jar;%CLASSPATH%" "-Dcatalina.home=C:\apache-tomcat-6.0.10" org.python.util.jython "-Dpython.security.respectJavaAccessibility=false" %ARGS%

後はそのバッチファイルを起動するだけ。


=
= 書くの忘れそうだったからあわてて書いた。 西尾泰和のブログ: タスクバーで目的のショートカットを選ぶまでの時間を短縮。 もうちょっとキャッチーなタイトルをつけたかったけど思いつかなかった。
= げげげ。 Jythonで「こんにちわ」ってファイルに保存したら、当然UTF-8だと思ったのにSJISだった。 うーん。 2.1ではコンソールの入力もSJIS、画面やファイルへの出力もSJISだから化けず、 一見うまく行っているように見え、 2.2では画面からの入力が何か別のものになったせいで化けていると考えるのが妥当だろうか。 文字コード周りは触れたくないんだがなぁ。
= ああ。Jythonで使えない最新のPythonの機能、デコレータもあったね。 デコレータ滅多に使わないので忘れてた。

デコレータなんて飾りですよ。 だってデコレーションっていうじゃない。

TomcatをJythonから起動したのと同じ方法で、 JythonをJythonから起動することもできるかも。

C:\jython-2.1>jython -Dpython.security.respectJavaAccessibility=false
Jython 2.1 on java1.5.0_10 (JIT: null)
Type "copyright", "credits" or "license" for more information.
>>> import org
>>> org.python.util.jython

>>> org.python.util.jython.main

>>> org.python.util.jython.main([])
Jython 2.1 on java1.5.0_10 (JIT: null)
Type "copyright", "credits" or "license" for more information.
>>> ^Z

>>>
できた、けど…いやー、別窓で開いて欲しいなぁ。 ああ、JythonからJyConsole(JFrameを使っている)を呼び出せばいいのか。
= TAKESAKO @ Yet another Cybozu Labs: gihyo.jp Web連載 - この先生きのこるために注目をあびる優れた技術を身につける この先生、きのこ?あびる優? 絶対わざとだ(笑)

2007年03月11日

甜茶日記

あ、はい、大阪から帰ってきました。

西尾泰和のブログ: 花粉症日記 に5日分くらいの日記がまとめ書きされているのは出来心です。

父親も花粉症を発症して、 甜茶エキスを摂取したら楽になったそうな。 というわけで僕も甜茶エキスを摂取することにしました。


= Tomcatのソースコードを読んだり、 JavaでSSHを使う(Javaプログラムがサーバ)方法を調べたり。

とりあえずTomcatをダウンロードすることにした。

で、起動するためのバッチファイルを読んだり。

:execCmd
rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
何かと思ったら、for文がないのか。 そんな古い言語は滅びてしまえばいいのに。
= Jython実行時にクラスパスを指定すれば、他のJARの中のクラスもインポートできる。 でも、「あらかじめホゲホゲしておけ」というのは親切じゃない。
>>> import java.net.URLClassLoader as CL
>>> cl = CL([r"C:\apache-tomcat-6.0.10\bin\bootstrap.jar"])
(略)
TypeError: java.net.URLClassLoader(): 1st arg can't be coerced to java.net.URL[]

>>> import java.net.URL as URL
>>> cl = CL([URL(r"C:\apache-tomcat-6.0.10\bin\bootstrap.jar")])
(略)
java.net.MalformedURLException: java.net.MalformedURLException: unknown protocol
: c
>>> cl = CL([URL(r"file:///C:\apache-tomcat-6.0.10\bin\bootstrap.jar")])
>>> cl.findClass("org.apache.catalina.startup.Bootstrap")
(略)
AttributeError: findClass
>>> cl.loadClass("org.apache.catalina.startup.Bootstrap")
<jclass org.apache.catalina.startup.Bootstrap at 10492028>
>>> b = _
>>> b.main([])
java.lang.ClassNotFoundException: org.apache.catalina.startup.Catalina
(略)
>>> b.main
<java function main at 7702450>
>>> from java.lang import *
>>> import jarray
>>> jarray.zeros(0, String)
array([], java.lang.String
>>> b.main(_)
java.lang.NullPointerException
        at org.apache.catalina.startup.Bootstrap.setAwait(Bootstrap.java:352)
(略)
うーん。 眠い。
= ちょっとしたメモ。
>>> [m.name for m in cl.class.methods]
['newInstance', 'newInstance', 'findResource', 'findResources', 'getURLs', 'load
Class', 'getSystemClassLoader', 'getResource', 'getResourceAsStream', 'getSystem
Resource', 'getSystemResourceAsStream', 'clearAssertionStatus', 'getParent', 'ge
tResources', 'getSystemResources', 'setClassAssertionStatus', 'setDefaultAsserti
onStatus', 'setPackageAssertionStatus', 'hashCode', 'getClass', 'wait', 'wait',
'wait', 'equals', 'notify', 'notifyAll', 'toString']
もちろんこのclってのはあるJavaのオブジェクト。

2007年03月08日

Jythonでハノイの塔の可聴化

Jythonを使うと5行でMIDIが鳴らせる。
>>> import javax.sound.midi.MidiSystem as MidiSystem
>>> synthe = MidiSystem.getSynthesizer()
>>> synthe.open()
>>> c = synthe.channels[0]
>>> c.noteOn(48, 127)
ding(n)で指定した音が0.25秒なるようにしてみる。
>>> def ding(n):
...     c.noteOn(n, 127)
...     sleep(0.25)
...     c.noteOff(n)
...
>>> ding(80)
ハノイの塔を解く。
>>> def hanoi(numPlate, frm, to, via):
...     if numPlate == 1:
...             move(frm, to)
...     else:
...             hanoi(numPlate - 1, frm, via, to)
...             move(frm, to)
...             hanoi(numPlate - 1, via, to, frm)
...
>>> def move(frm, to):
...     print frm, "=>", to
...
>>> hanoi(4, 1, 3, 2)
1 => 2
1 => 3
2 => 3
1 => 2
3 => 1
3 => 2
1 => 2
1 => 3
2 => 3
2 => 1
3 => 1
2 => 3
1 => 2
1 => 3
2 => 3
ハノイの塔の解法を音楽にする。 ソからミを経由してドへ。
>>> def move(frm, to):
...     ding(frm)
...     ding(to)
...
>>> hanoi(4, 55, 48, 52)
「jython -Dpython.security.respectJavaAccessibility=false」で起動したJythonを使っています。

2007年03月06日

花粉症日記

今年から花粉症を発症したみたい。 外に出ると目に異物感。 少し歩くと鼻とのどが痛くなり、 じきに鼻水が止まらなくなる。
= 風呂釜は壊れていなかった。 一度に使いすぎると機能停止するんだそうな。 外の湯沸かし器に付いているリセットボタンを押すと直るんだそうな。 直った。めでたしめでたし、っていうか修理が必要ないんだったら、 キャンプの前日でも問い合わせればよかった。
= IPSJ Digital Courier船井若手奨励賞受賞のメール。 添付のWord書類に賞金を振り込むための講座情報を書くように言われて、 何気なくダウンロードしたのだけども、 ふと思いついてGoogle Docsを試してみることに。

編集は何の問題もなくできたけども、 それを返信メールに添付する方法がわからず、結局一旦ローカルに保存。 無意味…。 まぁ、Wordの入っていない環境でもこの手のメールに返信できるのは便利。


= ITmedia Biz.ID:「ファイル名を指定して実行」の便利な使い方(その1)
しかも、「mshta [任意のURL]」と入力すれば、WebページをHTA(HTMLアプリケーション)として開くことも可能だ。HTAとして開いた場合は、Webページを描画しただけのウィンドウが立ち上がり、ブラウザのツールバーなどは表示されない。
スラッシュドット ジャパン | ITmedia記事が危険なHTAで外部サイトの表示を薦めている
mshta.exe は HTA ホストであり、ゾーンを無視して警告なしにスクリプトや ActiveX コントロールなどを動かすことができるアレでナニなモジュールだ
「rimo.tvをテレビのように使いたい」とかなら 「iexplore -k rimo.tv」でいいんじゃなかろうか。 Alt+F4で終了。
= [結] 2007年3月 - 結城浩の日記
品質を上げるのは量子的な作業であって、全体的にふわっとやっていてはなかなかうまくいかない。作業を区切ってその範囲に集中する、という作業が大事(あるフェーズでは)。
それだ!
= 今日はよく外国人に話しかけられる日で、 Pythonのチャットルームに13歳のタイ人の女の子が来て一度追い返したのに戻ってきたり、 台湾人の友達に別の友達を紹介されて色々話したり。 後者は相手が日本語上手すぎて英語の練習にすらならない…。

台湾の人って「か」を「が」にしてしまう傾向が強いね。 「そっか」をほぼ100%「soga」って書くし、 今回の日本語の上手な子も「そうなんですか」を「そうなんですが」とか書くし。


= あれだなぁ。 Jython2.1では
>>> print "こんにちは"
こんにちは
とちゃんと動いていたのに Jython2.2では
>>> print "こんにちは"
?±????????
となってしまう。
= 衝撃の事実。 首頁 - Wikipedia頭版 - 維基百科,自由?百科全書卷首 - Wikipedia封面 - Wikipedia。 一見中国語に見えるものだけでこんなにある。 さすが人数が多いだけある。
= 洟とか痰とか。
= 花粉症かどうか。 風邪で粘膜が荒れているのが主因で花粉に過敏反応しているのかも。 今日は外に出ても大丈夫だった。 昨日は風が強かったしなぁ。 あと昨日雨が降ったから花粉が洗い流されたのもあるかも。
= Javaのサンプルソースコードのパッケージ宣言がやたら長い問題 (org.nishiohirokazu.jythonbook....)に、 抜本的な解決策を思いついた。 どうして今まで気づかなかったのかが謎。

というわけでnhiro.orgを取りました。 http://www.hyuki.com/の真似。 org.nhiro.jybookにすれば短いね。


= 「演算子オーバーロード」って言葉は間違った使われ方をしていないか? 「Javaには演算子オーバーロードがない」と言われるけど、 整数と整数の「+」と文字列と文字列の「+」は別の挙動をするわけで、 これって演算子オーバーロードじゃないかと。 「演算子オーバーロードがない」という表現はOCamlのような 「整数の足し算は+で、浮動小数点数の足し算は+.」 なんていう言語に対して使う言葉じゃないのか。

n個のものをn+1個にできないことを「複数にできない」と言っている感じ。 まぁ、最初に与えられたn個から変化できないという意味では、 そのn個をひとかたまりのものだと考えれば「1を2にできない」になるわけだが。

で、そんなことはJython本の原稿には書かないのでここに書いて憂さ晴らし(ぇ)


= あうー。 スクリーンショットを賢く切り抜いてくれるソフトはないかなぁ。 これ書くの3回目くらいの気がする。

で、書くたびにAlt+PrtScとかCapture Stuffとかを紹介されるけども、 それじゃダメ。 例えばあるウィンドウの前にあるダイアログが出ているシチュエーションで、 そのダイアログだけ取りたい場合もあれば、後ろのウィンドウごと取りたい場合もある。 モーダルダイアログとは 【modal dialog】 - 意味・解説 : IT用語辞典 e-Words の場合、Alt+PrtScではそのダイアログだけを撮ってしまう。 右クリックででるメニューとかもある。Altを押したら消えてしまうことが多い。


= 肩がこったので体操の動画でもないかとYoutubeを検索。

YouTube:「アルゴリズム体操」をものすごい人数でやってみた

うわー、なんだこりゃーw。


= 引っ越し先まで結構太い道で迷わずにいけそう。 15キロちょい。 というわけでレンタカーでも借りて引っ越ししようかと思ったら、 レンタカーより赤帽の方が安かった。

4人乗りマルチワゴンなら9450円だから赤帽より安いかもなぁ。 こちらなら全部きちんと梱包しなくても適当に積んで行けばいいからなぁ。 どっちが楽かなぁ。

船橋営業所で借りて押上営業所で乗り捨てないで、 船橋営業所に返しに行ったとする。 20日の9時に借りて18時に返すのの見積もりで4人乗りワゴンが5,250円。

とりあえずどちらにしても部屋を片付けないとなぁ。


= 花粉症で病院に行くのが嫌なので、 とりあえず野菜をたくさん摂取。 晩ご飯はお鍋。 いつもは鍋の素を使うのだけど、 どこに売っているのかわからなかったので、 昆布と海塩で試してみた。問題なさそう。

YouTubeのラーメンズの動画を見ながら晩餐。 見たことない動画もあるなぁ。

やっぱり僕がラーメンズを面白いと思うのは、 小林賢太郎の方の感性にマッチしているんだろうなぁ。 片桐仁がエレキコミックとかとやっているコントがちっとも面白くない。

So-net blog:砂消しゴムで消せなかった物:エレ片に見えるラーメンズ片桐の可能性

書かれてるなぁ。 でもここに書かれているように、片桐仁のインタビューは面白かった。

小林賢太郎の組み立てがうまいんだなぁ。


= 予算使い切らないといけないんだよなぁ。 もう3月だし。 こう言うの苦手なんだよなぁ。 去年は使い切ったつもりが8万円ほど赤字で大変なことになったし。
= Amazon.co.jp:みんなのPython Amazon.co.jp: ふつうのHaskellAmazon.co.jp: たのしいRuby。 うーむ、「ひらがな4文字+言語名」ってのがはやりなんだろうか。 「やらかいJython」ってタイトルにするか…。

ちなみにタイトルは編集者さんが決めました。


= ASIMOがとんでもないことにwww - Google Video

対処が手慣れてるね(笑)


= ううう、お腹が痛い&首の後ろあたりから寒気が。 やっぱり花粉症じゃなくて風邪だったのだろうか。 風邪だから花粉に過敏反応したんだろうか。
= 小林賢太郎主演、企画椎名林檎のショートムービー 「百色眼鏡」を見ました。 短篇キネマ 百色眼鏡 - Wikipedia 怖かった。 ちなみに見たい人はYouTubeで見られます。
= いそいで原稿を書かないならどんどん現状に取り残されている…。 Jythonのページのダウンロード用のリンクがつけ間違っていて、 古いJython2.1は僕の説明通りにしてもダウンロードできないじゃん。

バグレポートにwebsiteってカテゴリもあったので、 レポートしてみた。

僕は基本的に新しいものを真っ先に使って人柱になるのはキライなので、 CPythonも2.5が出てからそれまで使っていた2.3を2.4にアップデートしたのだけども、、 なんだかんだで結局バグだらけのJython2.2betaを使って、 英語でバグレポートを書くハメになっている。 今は腰が引けているけども、Jythonをコンパイルできる環境が整えば パッチを投げてしまいそう。


= 大阪に帰ってきています。 確定申告するつもりだったのだけど、 源泉徴収されてるし、アントラッドからは交通費しかもらってないし、 というわけでしなくていいかも。 明日区役所で転出届を出して、月曜日にでも東京で転入届を出す予定。
= うーん。 たとえばMenuBarをdecapitalizeするとmenuBarになる、これはいいけど、 JMenuBarはdecapitalizeしてもJMenuBar。 それは自然な仕様なのか? Java Beansの仕様なのか?

PyJavaClass.java

private static String decapitalize(String s) {
    //return java.beans.Introspector.decapitalize(s);
    if (s.length() == 0)
        return s;
    char c0 = s.charAt(0);
    if (Character.isUpperCase(c0)) {
        if (s.length() > 1 && Character.isUpperCase(s.charAt(1)))
            return s;
        char[] cs = s.toCharArray();
        cs[0] = Character.toLowerCase(c0);
        return new String(cs);
    } else {
        return s;
    }
}

2文字目が大文字の際には何も小文字にしないでそのまま返すらしい。 まぁDNAがdNAになったら嫌な感じではあるけどなぁ。 そういう仕様なのかなぁ。


= Jythonのソースを読んでいると 「MRJ2.2.4のバグを回避するため」「Netscapeのバグを回避するため」 「Macの…」というコメントがあちこちに付いていて、大変だなぁと思うのだった。
= なぜJython本の原稿がなかなか進まないのか。 その理由はとても簡単。 「JButtonオブジェクトのactionPerformedにPythonの関数を代入するだけで、 イベントリスナが追加されます」 という説明では満足できなくて、 結局どういうメカニズムで動いているのかをソースを読んでしまうから。 僕が読者ならメカニズムが気になってしまうから。 でもそれじゃいつまでたっても原稿が仕上がらない。 僕が満足できる内容の本を完成させるには、 僕がJythonのソースコードをすべて読んで理解して、 その気になったら自分で実装できるようになった後でなければ書けない。 妥協しなきゃ。

90%の完成度のために1年かけるよりも、 3ヶ月で80%の完成度のものを作る方がよい場合もある。 理想は高く妥協は早く。

似たようなことは結城さんの書き物にもあったと思うけども、 確かそれには「100%の完成度のために…」だったと思う。 その言葉を自分なりに消化して再構築したら「90%の完成度のために…」となった。 僕にとって、100%の完成度とは、 Jythonのすべてのバグをつぶして、 初心者がとまどうような仕様は修正して、 Pythonを知らない人が見ても心引かれるようなサンプルやデモを用意した状態。 そんなことを考えていてはいつまでたっても原稿が進まないのは当然。 現状のバグや初心者にわかりにくい仕様は全部受け入れて、 それをなるべくわかりやすく解説するしかない。


= スタートメニューの中に1で始まる名前で、 Jython本の原稿をコンパイルするスクリプトへのショートカットを入れた。 Winキーを押して1を押せばコンパイルされる。

で、ふと気がついたのだけど、 …。 …。 言葉で説明するより実際に作る方が早そうだ。 原稿書きの息抜きってことにしよう。

できた。 コピー元にmycompというファイルとmydocというファイルがあると、 コピー先にm\y\compとm\y\docとしてコピーされる。 コピー元にショートカットをためておいて、 コピー先をスタートメニューの中にする。 そうすれば頭の決まり字を打つだけでアクセスできる。

前に紹介した「スタートメニューの中にショートカットを入れるフォルダを作ってそこにパスを通す」 というテクニックは、使っているうちにショートカットが増えてきてややこしくなる。 Firefoxを起動しようとしてFを押しても他のものと衝突しているせいで起動されず、 つい打ってしまったiのせいでインターネットエクスプローラーが立ち上がってしまったりする。 そこで、ショートカットをためておくフォルダを別に作って、そこからこのスクリプトでツリー化して スタートメニューの中に入れる。めでたしめでたし。

後でちゃんと独立した記事にする。


= やっぱり、核エネルギー書くエネルギーの総量は一定かも知れない。 日記を書かなければ、Jython本の執筆速度は上がるかも知れない。
= GRINEditの設計は方針が間違っていたかも知れない。 例えば頂点オブジェクトのgetParamsを呼ぶといろいろな属性の名前と値がハッシュになって返ってきたり、 hogeという名前のフィールドにアクセスするとgetHogeを呼び出したりと、 ダイナミックにグラフを操作できるように色々してきたわけだけど、 これってJythonの劣化コピーじゃないかと。 「Jythonを使うことを前提にした場合、どういう設計が好ましいか」を考えていたらこうなった。 当然ダイナミックな部分はJavaで書くよりもPythonで書いた方が楽なわけで、 自分でJavaでリフレクションを書くよりも、Pythonで書いた方が楽なわけだ。

現状、XML-RPCで操作するためのインターフェイスはかなり抽象度の低いものになっているけども、 そこらへんも含めて設計し直すべきだなぁ。


= Jythonを作ったJim Hugninは、実はAspectJも作っていたことが判明。

それはそうと、 フィールドをprivateにしてgetterとsetterを作るのが美徳であるような書き方の Javaの教科書が多い気がする。

int型のageってフィールドがあったときに、 それがpublicでどこからでもアクセスできるようになっていると、 後から「あ、これ年齢だから負にならないようにしよう」と思ったときに チェックのためのコードを追加するのが大変だからsetterを作る、という理解で正しいのかな。

でも、それってJavaが「力の弱い言語」だから、そういう書き方をしないといけないというだけのような。 アスペクト指向でコードが書ける言語なら、チェックのためのコードを追加したくなったときに 「ageというフィールドに対しての書き込みアクセスの前に、 書き込む値をチェックするコードを編み込む」ってだけのこと。 Javaがフィールドに書き込む処理をフックすることができない言語だから、 自前でフックするためのコードを用意する必要がある。それがsetterなのでは。

2007年03月04日

Python Developer's camp 日記

さて、とりあえず上野に行こう。

上野に着いた。

東京に来てからというもの、 ことあるごとに頭の中で曲がなる。 「♪JR新宿駅の東口を出たら~」とか。

「♪上野発の夜行列車降りたときから」ってのは 乗って降りてるから上野の歌ではないなぁ。 どこの歌なんだろう。

上野から新幹線が出ているとは知らなかった。 今まで僕にとって新幹線ってのは博多から東京まで運転しているものなので。

長野に着いた。

牛に轢かれて善光寺

長野電鉄。 ちょうど目的地行きの特急があった。 特急券は100円。リーズナブル。

P1060937
P1060937 posted by (C)にしお

全然雪が積もってないなぁ。 箱根登山鉄道みたいに山に登るのかと思ったら、 平らなところを走っている。 後で登るのかな。

箱根と長野の位置関係を後で調べよう。 たぶん長野の方が北だとは思うけど、 どちらが東なのかよくわからない。

千曲川。

もうすぐ終点って言われたのにまだ平らだ。

あ、ここから急勾配を登るんだって。

酔いそう。

湯田中の駅に着きました。 雪がありません。

P1060946
P1060946 posted by (C)にしお

あ、ここからバスに乗るんだった。

時刻表…の写真を撮ったつもりだったのに取れていなかった。

現在時刻は13時8分。うわっ、ラストのバスがもうすぐだ。 あと10分遅れてきていたらタクシーで行くはめになったかも。

登ったら雪がたくさんあった。

持ってきたSOYJOYがパンパンにふくれた。

P1060951
P1060951 posted by (C)にしお

サルが来たら捕まえてPythonを教えて 本物の「サルでもわかるPython」を作る計画。

だんだんにぎわって参りました。


= 20時。 僕のマシンが無線LANにつながらない。 PHSもつながりにくい。 Lingrが切れて再接続の繰り返しで全然発言できない。

Lingrに入っていると、回線状況が悪化したときにb-mobileの接続ダイアログが出てきて、 きっとプレゼンの邪魔になるので退室。

djangobook.com

13行でWordPressもどきができちゃう。

Jythonの発表終了。

無線LANをONにした状態でサスペンドすると、 再起動するまで無線LANがつながらなくなるような気が。

>>> from pprint import pprint
>>> pprint(vars(__builtins__))

import pdb;pdb.set_trace()

enthoughtにcoverageってライブラリがあって、便利らしい。

>>> import dis
>>> def foo(e):
	return e + 1

>>> dis.dis(foo)
  2           0 LOAD_FAST                0 (e)
              3 LOAD_CONST               1 (1)
              6 BINARY_ADD          
              7 RETURN_VALUE        

= Pythonで
# spam.py
import spam
をパスの通ったところにおいて、import spamすると spam.spam.spam…と無限にいける。
= 2日目。 初日は喉が痛かったが、 少し腫れてきた。 そして左の鼻の奥だけが痛い。 鼻水が止まらない。
= 僕の講義資料は Jython インタラクティブ・ハッキング クラスなんていらないさ! に置きました
= みんながTodoListを作っているから、 僕もネタとしてワンライナーで作ろうかと思ったけども、 設計しているうちにまともに作りたくなってしまった。

優先度はなし。デッドラインはNoneもOK。 重要なフィールドはrelyOnで、 Todoが別のTodoに依存しているかどうかを記述できる。 Todoはデッドラインが近いほど優先度が高く、 多くの優先度の高いTodoがrelyOnしているTodoは優先度が高くなる。

relyOnは推移律を満たさないといけないけど、 それを弱めたような「タスクAをやってからのほうがタスクBが楽にorいいクオリティでできるかも」 という関係を入れても面白いかも知れない。 で、循環参照が起きても構わないようにして、 最終的にどれの優先度が高いかはGoogle PageRank的なアルゴリズムで決める。


= ライトニングトーク。 スケッチブックメソッド。 逆に新しい。
= いろいろ勉強になった。 4月になったらDjangoを勉強しようかと思っていたけど、 Ploneをいじってみたい気もしてきた。

typoで動かなかったときに、typoそうなところを見つけてくれるプログラムがあると便利なのでは。 re.findall("[_\w][_\w\d]*", data)した後で、よく似ているペアをtypo候補として提示する。


= そうか。遅延評価か。

モードを指定しないでも、呼んだメソッドによって適当な方法で開いてくれるファイルオブジェクト。

>>> class myfile(object):
	def __init__(self, filename):
		self.filename = filename
		self.file = None
	def _ensure_opened(self, mode):
		if not self.file:
			self.file = file(self.filename, mode)
	def write(self, s):
		self._ensure_opened("w")
		self.file.write(s)
	def read(self):
		self._ensure_opened("r")
		return self.file.read()
	def close(self):
		self.file.close()

		
>>> f = myfile(r"c:\hoge.txt")
>>> f.write("Hello!")
>>> f.close()
>>> f = myfile(r"c:\hoge.txt")
>>> f.read()
'Hello!'
>>> f.close()

= 上のようにした場合はreadlineとかを引き継ぐのが面倒。
>>> class myfile(object):
	def __init__(self, filename):
		self.filename = filename
		self.file = None
		def bind(name, mode = None):
			def foo(*args, **kw):
				f = self._get_opened_file(mode)
				method = f.__getattribute__(name)
				return method(*args, **kw)
			self.__dict__[name] = foo
		bind("write", "w")
		bind("read", "r")
		bind("readlines", "r")
		bind("close")
			
	def _get_opened_file(self, mode = None):
		if not self.file:
			self.file = file(self.filename, mode)
		return self.file

	
>>> f = myfile(r"c:\hoge.txt")
>>> f.write("Hello!")
>>> f.write("Hello!2")
>>> f.close()
>>> f = myfile(r"c:\hoge.txt")
>>> print f.read()
Hello!Hello!2
>>> f.close()
こういう「ほとんどのメソッドを書き換える必要がある」ケースならば、 「親クラスのメソッドを変更しないで引き継ぐことができる」継承を使ってもメリットがほとんどない。
class myfile(object):
	def __init__(self, filename):
		self.filename = filename
		self.file = None
		def bind(name, mode = None):
			def foo(*args, **kw):
				f = self._get_opened_file(mode)
				method = f.__getattribute__(name)
				return method(*args, **kw)
			self.__dict__[name] = foo
			
		for name in dir(file):
			if name.startswith("write"):
				bind(name, "w")
			elif name.startswith("read"):
				bind(name, "r")
			else:
				bind(name)
			
	def _get_opened_file(self, mode = None):
		if not self.file:
			self.file = file(self.filename, mode)
		return self.file

>>> f = myfile(r"c:\hoge.txt")
>>> f.write("Hoo\n")
>>> f.write("Foo")
>>> f.close()
>>> f = myfile(r"c:\hoge.txt")
>>> f.readlines()
['Hoo\n', 'Foo']
>>> f.close()
こういう「決まったパターンでメソッドを書き換える」というケースだと、 やっぱり上みたいにアスペクト指向的なアプローチをするのが楽。
= MercurialHG
= 帰ってきた。なんだかどっと疲れた。 鼻水が止まらないし。
= Gopher: missingpy
MissingPy is a Haskell binding to Python and library of Python interfaces for Haskell.

これを使えばHaskellでPythonのライブラリが使えるのかな。

MissingPy permits you to call Python code from Haskell. It does NOT permit you to call Haskell code from Python.
逆は無理らしい。
= typoチェッカー。 レーベンシュタイン距離 - Wikipedia を使って、二つの単語の距離を決める。
>>> def calcLevenshteinDistance(s1, s2):
	SKIP_COST = 1
	DIFF_COST = 1
	class MyMat:
		def __init__(self):
			self.value = {}
		def get(self, i, j):
			if i == -1:
				return (j + 1) * SKIP_COST
			elif j == -1:
				return (i + 1) * SKIP_COST
			else:
				return self.value[i][j]
		def set(self, i, j, value):
			if not self.value.has_key(i):
				self.value[i] = {}
			self.value[i][j] = value

	mat = MyMat()
	l1 = len(s1)
	l2 = len(s2)
	for (i, c1) in enumerate(s1):
		for (j, c2) in enumerate(s2):
			cost = 0
			if c1 != c2: cost = DIFF_COST
			mat.set(i, j, min(
				mat.get(i - 1, j - 1) + cost,
				mat.get(i, j - 1) + SKIP_COST,
				mat.get(i - 1, j) + SKIP_COST))
	return mat.get(l1 - 1, l2 - 1)

>>> calcLevenshteinDistance("Hello", "Hollo")
1
>>> calcLevenshteinDistance("Hello", "Hello")
0
>>> calcLevenshteinDistance("Hello", "Helo")
1
で、こんな感じで似ている順に表示してみる。
>>> def typoChecker(data):
	import re, sets
	THRESHOLD = 0.75
	candidate = []
	words = list(sets.Set(re.findall("[_\w][\_\d\w]*", data)))
	for (i, w1) in enumerate(words):
		for w2 in words[i + 1:]:
			d = calcLevenshteinDistance(w1, w2)
			l = len(w1) + len(w2)
			s = float(l - d) / l
			if THRESHOLD < s:
				candidate.append((s, w1, w2))
	candidate.sort(reverse = True)
	for c in candidate: print c
入力するデータはこんなもの。さてどこがtypoでしょう。
>>> data = """
class myfile(object):
	def __init__(self, filename):
		self.filename = filename
		self.file = None
		def bind(name, mode = None):
			def foo(*args, **kw):
				f = self._get_opened_file(mode)
				method = f.__getattribute__(mame)
				return method(*args, **kw)
			self.__dict__[name] = foo
			
		for name in dir(file):
			if name.startswith("write"):
				bind(name, "w")
			elif name.startwith("read"):
				bind(name, "r")
			else:
				bind(name)
			
	def _get_opened_file(self, mode = None):
		if not self.file:
			self.file = file(self.filename, mode)
		return self.file

"""
出力結果は下記。
>>> typoChecker(data)
(0.94736842105263153, 'startwith', 'startswith')
(0.875, 'mame', 'name')
(0.83333333333333337, 'for', 'foo')
(0.8125, '__dict__', '__init__')
(0.80000000000000004, 'file', 'myfile')

= 帰りは柴田さんの車に乗せてもらいました。 執筆はマラソン。

2007年03月01日

風呂釜壊れた日記

あ、そうだ。 昨日新居の契約をしてきたってことを書くの忘れてた。 まぁいいや。

あとmixiがSecond life内でしか見られない動画を用意して、 仮想空間でのリクルーティングを始めたということとか、 厚生労働省がメタボリックシンドロームの社員を減らすことができない健康保険には、 お金をたくさん拠出させることを検討中とか、そういうのも書き忘れた。

NIKKEI NET:メタボリック減らないと健保の負担金増額・厚労省検討


= ゲーム機の進化を見ていると、 地上波デジタルで高画質になったテレビより、 直感的な操作で参加できるテレビの方がウケるのかなぁ、とふと思った。
= 風呂釜が壊れてお湯が出ません。

いつでも温かいお湯が出せるのは幸せなんだと痛感しました。

お湯は出ないけどとりあえずレンジで蒸しタオルを作れるし、部屋は暖かいし。


= 毎日毎日、セブンイレブンでこしあん大福とあらびきポークフランクを買って食べてしまう。 体重計るのが怖い。
= 「あたま」「なかみ」…「なかみ」「まとめ」という構造の文章を 「章リード」「節リード+節」…という構造に変換するには、 「あたま」と「まとめ」を章リードにできるくらい削るか、 ふくらませて「はじめに」の節にするかのどちらか。
= 2の24乗(16777216)の覚え方。 「色、な、な、何色?」。 知らない女性に電話をかけて下着の色を聞くつもりで。
= 朝。 8時半に自然に目が覚めるという「よい兆候」を示していたのに、 お腹が痛くてお腹が空いて寒くて頭がかゆかったのでパニックになって、 とりあえずもう一度寝てみた(ぇ)

で、起きたら12時だし。近くの小学校のチャイムで目が覚める。

少なくとも、空腹状態から単に4時間経っても何も解決していないはずなのに。

ららぽーとの湯 常盤殿 とりあえずららぽーとにスーパー銭湯があることはわかった。 今から行こう。ボディソープがあるかどうか書いてないけど、たぶんあるんだろう。 タオルは一応持って行くかな。


= 短い記事と長い文章の違いは、 ライトニングトークと40分間の発表の違いに似ているのかも知れない。 ライトニングトークはテンポやリズムやネタや畳みかける攻撃とかが有効なのだけど、 そのノリを40分維持するのは発表者も視聴者も大変。
= 最新Pythonエクスプローラ~Django,TurboGears,Twisted,IronPython 完全攻略|gihyo.jp。 見本誌が届きました。 僕と同じセクションで扱われている話題は、DS Python、IronPython、Python3000。 えっと…どうしてこれの続きとして「学術系で使えるPython」というお題を選んだのか謎。 僕だったらJythonを選ぶけどな。 そしてJythonを選んでいてもやっぱり僕が書くことになった気が。
= Jython本のサンプルのJavaコード、ひとかたまりごとに package org.nishiohirokazu.jythonbook.sec3.sample8; とパッケージを分けていたら、すごく長ったらしくなってしまった。 org.nishiohirokazu.jybook に全部入れちゃおうかなぁ。 もしくは章ごとに分けて org.nishiohirokazu.jybook.sec3 にするか。