« 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の発音で、仮