Diary?::2009-02

2009-02-01
Sun

(18:15)

age += 1 # Python に単項インクリメント演算子なんぞない

というわけで、四捨五入すると 30 になる年齢になってしまった。

(22:17)

でまあ今日は俺の誕生日って事で家族と飯食ってカラオケ行ってきたんだが、

  1. 俺が Carcass とか無茶苦茶なメタルを入れる
  2. 妹たちが Sound Horizon を入れる
  3. 最初に戻る

とまあいつも通り無茶苦茶なカオスになって、何かえらいこと喉を消耗した。

あと「『アヴァロンコード』、精霊となかなかフラグが立たないんだけどどうすんの?」とか聞いてくる妹二号は相変わらずだと思った。

2009-02-02
Mon

(21:45)

諸事情により作業スケジュールに余裕ができて、今週一週間は定時上がりが基本になりそう。というわけでエトリア冒険記を進めているのだが、今になってセブンスドラゴン発売までに終わる気がしなくなってきた。予定では今日中に第2階層分を終わらせるつもりだったけど、文章が上がるのは多分明日。

2009-02-03
Tue

(20:22)

唐突に「チョコ食いてえ」と思ってコンビニ行ってきたら、何かパッケージが鏡反転したチョコが売ってた。

まあだからなんだって気もするが。

あと先手を打って書いておくけど、妹二号は「男性から男性へのチョコレートは何というのでありますか?」とかいう文面のメールを送ってくるんじゃねえぞ。

(21:31)

そういや Adagio の新譜の "Archangels in Black" の輸入盤って既に発売されてんだよな。でもこのバンド、毎回毎回ボーナストラックも実にいい仕事しているんで、それ目当てに待つ価値は充分ある。デビューである "Sanctus Ignis" の "Nozama" はデモバージョンとは思えないクオリティだったし、続く "Underworld" の "Missa Aeterna" そして前作 "Dominate" の "Undying" とアルバム本編に決して負けていない曲だったんで、今回も国内盤まで待つ予定。ただ、それでも来月末発売ってのはなあ。

ちなみにこれはどこぞのボンクラが Adagio の "In Nomine..." という曲にパッションとかいう映画(見たこと無いんでわからん)のワンシーンをはめ込んだマッド。あまりに雰囲気にあっているので多分オフィシャルと言っても通じると思う(ってか前にも貼ったかなこれ)。

(23:20)

エトリア冒険記更新。今回は第2階層突破まで。最初にプレイしたときはレベル 34 ぐらいでクリアしてたけど、そっからレベルが 8 も低くても余裕だった。鞭ダークハンターのいいところは、ちゃんと特性を把握して使えば多少のレベル格差は無視して勝てるところだ。というかだな、ケルヌンノスはアルケミストかダークハンターのどちらかがいない場合、レベル 30 以上ないと厳しいと思われる。理由はクロスカウンター。

それにしても初回プレイ時もそうだったが、大体第3階層の途中ぐらいまでは本当にアルケミストはパーティの主力なダメージ源で実に輝いていたんだよ。その後アルケミストがどうなるかは既にプレイしたことのある人ならご存知の通り。まあその辺の展開はエトリア冒険記でも書いていく予定。

2009-02-04
Wed

(21:30)

俺は普段 ShowImg を画像ビューワーとして使ってるんだが、こいつはどうも同時に一つのプロセスしか立ち上げられないらしい。なので、とある仮想デスクトップで ShowImg を使っているときに別の仮想デスクトップで ShowImg を起動しようとすると、元の仮想デスクトップで起動していた ShowImg が引っ張られてくると。

……こういうアプリケーションを作りたくなる気持ちもわかるけどさ、でもこれ俺には単に不便なだけにしか思えないな。

2009-02-05
Thu

(20:11)

研修生の子とかに「プログラミングが上手くなる方法はないですか?」とか「効果的なプログラミングの学習方法はありますか?」とかいうのを相変わらず聞かれるんだが、んなもん俺に聞かれてもなあ。ぶっちゃけ俺は気がついたら上達してたタイプで、その要因を分析してみると「とにかくいろいろあった」となってしまう。

というわけで(どういうわけだ)思いっきり放言させてもらうと、結局プログラミングが上達するかどうかってのは、あるがままを受け入れないセンスに依るんじゃないかなあと思う。具体的には "#include<...>" を「おまじない」と言われても納得しない感性というか、自分の知性の限界に達するまで考え抜く姿勢というか。

「作りたいソフトウェアがあればプログラミングは上達する」というのは俺もそう思っていた時期がなくもないし、それが当てはまるケースもあるとは思う。でも作りたいソフトウェアがはっきりしていて実際に作ってるのに壊滅的な腕前の奴もいて、それは一体どうしてなのかと考えると上に書いた話になってくる。実際の所「おまじない」をそのまま何も考えずに受け入れても作れてしまうソフトウェアってのはかなりあって、そしてさらに「それでいい」と思ってしまう奴もかなりいて、まあ「おまじない」に限らず「それでいい」の閾値が低すぎる奴はなかなか上達しないよな。

とはいえまったくの未経験で入社してくる子ってのはどこまで考え抜けばいいか以前に知識ゼロだから、考え抜けるようになるためにも知識をつける必要がある。先に書いた「作りたいソフトウェアがあればプログラミングは上達する」というのが効いてくるのは多分ここで、作りたいものがある奴は勝手に知識を吸収するし、知識が付けば思考の深さの最大深度も深くなるだろ。そして特に作りたいものがない子は実際の現場で納期に終われながら知識を付ける他なくて、それって果たして幸せなのかねえ。あくまで仕事と割り切っているなら大丈夫かもしれないけど、でも一日最低8時間を週5日というのは、割り切るには長すぎる時間に思える。

(23:00)

エトリア冒険記更新。今日は1話のみで、やってることはゴーレム撃破のみ。割と激戦だったけど、こういう戦いをしておかないとぶっちゃけ第5階層まで物凄い激戦ってないからな。

ちなみに一般的にはゴーレムはレベル30台後半から挑むらしいが、ダークハンターとバードとアルケミストがいればレベル20台後半で勝てたりする。スキルを絞ればレベル20台前半でも大丈夫かもしれない(その分運が大きく絡むが)。

2009-02-06
Fri

(22:55)

カズフサってラブやんとくっつくしかないよなあ。いや「それが王道の展開だ」という意見もあるだろうけど、カズフサが成長した度合いよりもラブやんがダメになってる度合いの方が大きくて、それがフラグの立ちそうな要因になってるのがこの漫画のブルータルなところでね。

ついに葛西おじさんが出てきたと思いきや、笹塚刑事がシックスをぶち殺そうと単独行動に出るという急展開っぷり。っていうか笹塚とシックスの因縁がとんでもなくロングパスな伏線で驚いた(単行本4巻からの伏線だった)。

「いくらなんでもこれは盛大にミスってるだろ」と思って読み返してみたら、笹塚一家惨殺事件が X の仕業だと断定できない描写になってて驚いた。当初の予定では X をラスボスに据えて終わらせる予定だったらしいけど、そっからいくらでも展開が変えられるように描いていたってことか。本当に新人なのかこの人。

(23:36)

この一週間、一体俺は晩飯に何を食っていたのか思い出してみたらこうなった。

月曜
よくわからんハンバーグ店(御茶ノ水のディスクユニオンのある通りにあった)
火曜
カレー屋ジョニー(やはりディスクユニオンのある通り。とある改札を出てすぐだけど、改札口の名前がわからない)
水曜
豚骨ラーメン一本で勝負してるラーメン屋(店名不明。前述のハンバーグ店の隣の一階)
木曜
ココイチ(去年の9月ぐらいに最寄り駅の近くにあることが判明)
金曜
月曜と同じハンバーグ店

自分でもツッコミどころ多過ぎでよくわからん。

2009-02-07
Sat

(21:47)

世の中にはドゥーム/ストーナー/スラッジと呼ばれるジャンルの音楽があって、それについての簡単な説明は前に書いた。それらの音楽も充分凶悪な音楽なんだけど、それに飽き足らずにさらなる極北を目指した連中は特に「ドローン」と呼ばれるらしい。中でも Sun O))) とかは相対的に有名な部類だけど、どっちにしろ多分普通は知らないだろうし知らなくても問題ない。

で、今日紹介する Khanate というバンドはそういったドローンサウンドのそのまた極北。いや俺ドローンはあんま詳しくないけど、これよかヤバいサウンドの存在は考えたくないな。以下は彼らの多分プロモーションビデオだけど、「地獄のような絶叫とノイズにまみれて拳銃自殺する男」という極悪非道な代物なので、そういうのが嫌いな人は見ない方がいい。

ちなみに Khanate の音楽はドゥーム系専門レビューサイトの「静謐の森で」以下のような評価をもらっている。

第1曲 「Pieces Of Quiet」 のデュービンの第一声が聴こえた時点で嫌悪感がきたリスナーは、このバンドをあっさりとあきらめてプレイヤーの停止ボタンを押すべきだろう。音楽はなにも楽しいものばかりではない。

いやマジでこの評価の通り、音楽というよりも「音が苦」なサウンドだ。ホラー系の映像作品とかに嵌め込むと信じられないぐらいハマりそうなサウンドだけど、そうでもしないと俺には理解不能な世界だった。

2009-02-08
Sun

(12:55)

いい加減に衣類の整理をしようと思ってクローゼットの中を引っ掻き回したら、持ってる服の 90% が黒で 9% が白、どっちでもないのはカラーコードでいうと #403d3f ぐらいのカーゴパンツだけと改めてみると酷い状態だった。いやまあ、メタラーなんで黒っぽい服ばかりになるのは自然の摂理なんだが。

(19:33)

エトリア冒険記を更新。一応クイーンアントを倒したところまでで、余裕があればこの先も今日中にアップできるかも。

難易度的には明らかに第2階層の方が上で、こっから先は第6階層に到達するまではそこまで大変な事にはならない。一方でストーリーの方はこの階層から本格的に動き出す感じで、俺のパーティもそれに合わせてと言うわけじゃないけどターニングポイントが近い。

あと初回プレイ時よりもかなりレベル抑え気味だから、初回プレイ時には使ってなかった防御陣形を使うハメになっていて、それがパラディンのシールドスマイト取得への足枷になりそうだとか、結構大変だ。初回はレベル 30 後半で突破してたところを今は 30 未満でやってるからなー。

2009-02-09
Mon

(20:51)

今日は久しぶりに一日中 Linux サーバの構築とかの作業だった。もうちょっと具体的に言えば仮想化を使ったサーバ群の集約。

何で仮想化なんぞを始めたかというと、これまで社内で管理してたサーバが結構古くなってハードウェア的にヤバげだったり、 Web アプリケーションのデモ用途にものっぴきならない事情でマシンが丸々一台必要だったり(勿論クライアントマシンのお下がり)、いろいろ問題が噴出していて俺を含めた管理者全員がうんざりするようになったんで、思い切って仮想化して集約しようという事になった。というか「何とかサーバ群をまとめられないか」と上司に聞かれたんで脊髄反射で「仮想化すりゃ良くね?」と答えてしまったんで、結局また俺がやるハメに陥ったわけだが。

もっとも今日やったのは仮想化して AP サーバを動かして、どれぐらいパフォーマンスに影響が出るのかとか、運用手順がどうなるのかとか、その辺を調べるためのリハーサルで、本チャンはまだまだ先なんだが。

しかし俺は本来はシステム・ネットワークの管理は管轄外なんだがなあ。何でターミナルでコマンド叩けるとかシェルスクリプトが多少書けるとかの理由だけでこんな事やってんだか。こういうのも楽しいからいいっちゃいいけど。

(22:51)

いくら何でも寒すぎるだろ。

2009-02-10
Tue

(23:50)

いやー、やっぱ酔っ払いの相手は疲れるなー。今後は他社さんとの交流という名目があっても酒の入る席には二度と行かないつもりだが、とりあえず上司には「今後また俺の前で泥酔して醜態を晒したら会社を辞める」と言っておいた。

2009-02-11
Wed

(15:57)

試しに arora という Webkit ベースのブラウザを使ってみたが、今のところはちょっと微妙。何が微妙って、まだ Flash をきちんとサポートしてないところが一番微妙。他の部分もキーボードショートカットとかいろいろ未熟だけど、まあ使えるには違いないか。売りの一つである Web Inspector はなかなか面白いかもしれないけど、俺は Web 系じゃないので真価のほどを評価するのは無理だな。

(23:27)

エトリア冒険記更新。今回は第3階層クリアまで。いよいよアルケミストが活躍できなくなってきた。何しろスキルポイントが足りないのでボスに合わせて最大火力を叩き込むのが難しく、それが出来たところで戦局を動かすには至らないという有様。道中は全体術式で雑魚を焼き払えて便利なんだが、別に全体術式がないならないでなんとかなってしまうしな(より厳しいはずの世界樹IIでもそうだった)。

2009-02-12
Thu

(23:21)

単に実装インターフェースの都合で空メソッドになってるはずのところに「TODO: 実装予定」とか無茶苦茶なコメントを残して離任した前任者を全力で殴り飛ばしたい気分。何せ類似バグの調査中に見つかったからな、それが。しかもそいつの担当箇所に全部それが書いてあって、どれがマジもんの未実装部分でどれが単なる空メソッドなのか、片っ端から調査するハメになっちまった。

2009-02-13
Fri

(22:25)

ドラクエ9が延期らしいが、元々買う予定のなかった俺にはまったくもってどうでもいい。そして「どうでも良くない!」という人たちは、浮いた予算でセブンスドラゴンを買いましょう。

しかしセブンスドラゴンやってる暇あるかな、来月。ここ数日の動向を見る限りではかなりヤバめというか、もういい加減俺一人の努力でどうにかなる範疇を越えているというか、「きちんと単体テストを書きましょうね」レベルから説明しないといけないとは。

2009-02-14
Sat

(10:51)

とある理由により Python でバイナリデータを弄くり回す必要が出てきて、そういう時には struct モジュールを使うことがあるんだが、こいつにちょっと罠があって軽くハマった。

>>> struct.calcsize('b') # char 1個分のサイズ
1
>>> struct.calcsize('i') # int 1個分のサイズ
4
>>> struct.calcsize('bi') # char と int それぞれ1個ずつのサイズ
8

何勝手にパディングしてんだよ! まあ大体予想は付くけど(どうせ適当なバイト境界にアラインメントしてんだろ)、とりあえず Python の struct モジュールのソース(実体は C)を読んでみるか。ちなみにバージョンは 2.5.4 な。

該当するソースは Modules/_struct.c で、ざっと目を通して目についたのは次の構造体。

typedef struct _formatdef {
    char format;
    Py_ssize_t size;
    Py_ssize_t alignment;
    PyObject* (*unpack)(const char *,
                const struct _formatdef *);
    int (*pack)(char *, PyObject *,
            const struct _formatdef *);
} formatdef;

alignment なんつーもろなメンバがあるからこれでビンゴだろ。それでこの formatdef 構造体はネイティブ、ビッグエンディアン、リトルエンディアンといったケースで場合分けされていて、それらは (native|bigendian|lilendian)_table[] として宣言されている。

static formatdef native_table[] = {
    {'x',   sizeof(char),   0,      NULL},
    {'b',   sizeof(char),   0,      nu_byte,    np_byte},
  :
  :
static formatdef bigendian_table[] = {
    {'x',   1,      0,      NULL},
#ifdef PY_STRUCT_OVERFLOW_MASKING
    /* Native packers do range checking without overflow masking. */
    {'b',   1,      0,      nu_byte,    bp_int},
  :
  :
static formatdef lilendian_table[] = {
    {'x',   1,      0,      NULL},
#ifdef PY_STRUCT_OVERFLOW_MASKING
    /* Native packers do range checking without overflow masking. */
    {'b',   1,      0,      nu_byte,    lp_int},
    {'B',   1,      0,      nu_ubyte,   lp_uint},
  :
  :

それでこの native_table[] で作られてる formatdef 構造体を見ると、そこで int や long にアラインメントが指定されてるんだな。これは他二つには無い。

{'h',   sizeof(short),  SHORT_ALIGN,    nu_short,   np_short},
{'H',   sizeof(short),  SHORT_ALIGN,    nu_ushort,  np_ushort},
{'i',   sizeof(int),    INT_ALIGN,  nu_int,     np_int},
{'I',   sizeof(int),    INT_ALIGN,  nu_uint,    np_uint},

ちなみにこのアラインメントは以下のようなマクロで定義されている。

typedef struct { char c; int x; } st_int;
#define INT_ALIGN (sizeof(st_int) - sizeof(int))

ダミーの char を含む構造体を定義して、それに対してオフセットを計算する、と。そしてこのアラインメントを使ってる関数は次の align 関数だけで、さらに align 関数は prepares_s 関数でしか使われていない。実にわかり易いね。

static int
align(Py_ssize_t size, char c, const formatdef *e)
{
    if (e->format == c) {
        if (e->alignment) {
            size = ((size + e->alignment - 1)
                / e->alignment)
                * e->alignment;
        }
    }
    return size;
}

大体謎は解けたな。先の 'bi' というフォーマットを例に処理を追っていくと、

  1. 'b' はアラインメントの対象ではないのでやる事なし。この時点で全体のサイズは 1 バイト
  2. 'i' はアラインメントが指定されているので、先の 'b' のサイズは ((1 + 4 - 1) / 4) * 4 で 4 バイト
  3. そこに 'i' のサイズである 4 が加算されるので、 'bi' というフォーマットのサイズは 8 バイトになる

という処理になる。ぶっちゃけ当初の予想通りだったけど、確かめてみるに越したことはない。

で、こういう勝手なアラインメントをさせないためには、良きに計らえでフォーマットを指定せずに、明示的に "=(アラインメントなしのネイティブバイトオーダ)", ">(ビッグエンディアン)"などを指定する。

>>> struct.calcsize('>bI')
5

やっぱこういう操作をやる時は、下位層で起こっていることがわかんねーとダメだな。

(19:26)

bk1 の検索システムはちょっと腐ってる。商品を検索した結果が1件だけだったらダイレクトにその商品のページを表示する事自体は別にいいんだが、その時点の URL は検索機能の URL のままで、商品のページの URL を知る方法はページ右下のパンくずリストからたどる他無い(画像の URL から類推できなくもないが)。そしてより目につきやすいページ上部のパンくずリストは「トップ > 商品詳細」という代物で、右下のパンくずリストに気がつかない人も結構いるんじゃないかと思う。というか、俺自身が今日になるまで気がついてなかったんだが。

(20:58)

久々に腹抱えて笑った Web 漫画。不条理というか意味不明というか、カオスな漫画が多いけど、その分ツボにハマったときの爆発力は異常。とりあえず俺のツボに来た奴をいくつかピックアップ。

奥様は魔女
ストレートかつブラックで良い。
トラウマママ
うすた京介っぽい? ウサギ達の表情がなんともいえない。
こぶとりじいさん
綺麗に起承転結になっていて、それでもなお意味不明。何やってんだこのじいさん。
畜産Now!
この内容でこのタイトルというセンスは本当に凄い。
水溶性マン
タイトルで落ちてる。
餅に詰まる
一体何があったんだ。
高橋くん
どう考えても何もかもがおかしい。どういう発想してるんだ。
コーヒーえもん
コーヒーカップの中身を見て盛大に吹いた。のび太の表情もいい味出してる。
ドラムえもん
神としか言いようがない。これは反則だ。

しかしこのサイト、 2006 年からやってたのか。全然知らんかった。

2009-02-15
Sun

(22:11)

明日は本社じゃなくて客先に直行なんだが、何かそこまでの道がスゲーうろ覚え。いや、駅に着いてちょっと歩けば多分思い出せるだろうなという程度には覚えているんだが、俺は駅から徒歩 15 分で着くところに 1 時間以上かかったという大変な前科を持っているからな。

そういえば池袋のジュンク堂も最初に行ったときは「マツモトキヨシのある通りを歩けば辿り着くはずなんだけどなー」とかいいながらまったく逆の改札から出てしまって、本来の数倍の時間がかかったんだっけ。

2009-02-16
Mon

(20:01)

今日の明け方枕元でガサゴソ音がしているので目覚めたら、鼠が走り回っていやがった。それでよりによって買ったばかりの服に齧歯類が噛み切ったような痕跡が……。これはやってらんねえ。なるたけ早く対策せねば。

2009-02-17
Tue

(23:54)

エトリア冒険記更新。今回は第4階層突破まで。どうも大抵はレベル 40 後半から 50 前半はないと厳しいという声があるみたいだけど、もっと低くても全然大丈夫だった。確か俺は最大レベル 55 ぐらいのパーティで挑んだんだよな、最初にやったときは。それよか平均でレベルが 14 ぐらい低くても、ちゃんと考えてスキルを振ればどうにかなるもんだ。

俺は諸事情により使ってないけど、医術防御を解禁してレンジャーを入れれば平均レベルはもっと低くても大丈夫なはず。逆にダークハーンターとカースメーカーのコンビを使わないと、もうちょっとレベルは必要かも。

2009-02-18
Wed

(21:08)

クソの塊のようなフレームワークを叩き壊して新しいフレームワークとのブリッジを作り、既存のアプリケーションを新フレームワークに移行というミッションが発動されたのだが、その旧フレームワークが本当に凄かった。

  • ビューとモデルを分離してると思いきや、モデルがビューに強烈に依存してる
  • ってか全体的に依存関係がスパゲティというかスワッピングパーティー
  • 戻り値の型が Object で、その戻り値が Boolean だったり String だったり Collection だったり
    • こんなの動的言語でもやらないよ
  • DTO のようなクラスに「分類コード1,2,3...」のようなメンバがある、というかそんなんばっか
  • スーパークラスのクラス名が「BusinessComponent1,2,3...」
  • もちろん Javadoc は俺が閻魔様だったら舌を引っこ抜くどころか脊髄を引っこ抜くレベル
    • 「未使用につき null でもよい」とされている引数がちゃっかり使われているとか
  • 調査に赴いた俺に渡されたソースは、ビルドがまったく通らなかった

えーと、冒頭の「クソの塊のような」ってのは訂正。クソそのものだ。

(21:59)

ちょっと前に妹二号にアヴァロンコードをあげたのだが、俺の予想を裏切ってきっちりクリアしやがった。あのいろいろ終わってるインターフェースと一部のボス敵で投げると思ったんだが、どうもそこは問題にならなかったようで。いやー、「萌え」の力って凄いなと(ただし世界樹には負けたようだ)。

しかしアヴァロンコードは続編出るのかね。俺はシステムの発想自体は凄くいいと思っているので、インターフェースを改善すれば大化けすると期待してる。

それと預言書の使い方はもっといろいろあっていい。例えば「街の人に病のコードを大量に付けて病気にして、ダンジョンで拾った薬草を高値で売りつける」とかそういうギミックは結構面白いと思うんだが。あとは付けたコードの取り外しに適切な制限を加えれば、「報酬を多く貰えるが敵を弱体化できなくなって難易度上昇」みたいなトレードオフが発生して、遊び方の幅が広がると思う(当然、治療が遅れると死ぬ)。「闇のコードで治安を悪化させまくって街の中でも戦闘開始」とか「森のコードで街をジャングル化して文明崩壊」とか、いくらでもアイディアはあるっしょ。

問題はこれらのシステムは作る手間がかなりかかりそうで、そしてそれ以上に普通に不道徳というか不謹慎なので多分チェックを通らない。特に「街の人をガチの病気にする」という発想は確実にアウトだろう(GTA どころか POSTAL2 だ、それは)。

2009-02-20
Fri

(00:42)

檜山さんのセミナーに行ってきた。報告はまた後で。とりあえず風呂に入ってくる。

(01:02)

というわけで、檜山セミナーの感想というか個人的なまとめをやってみる。何でこんな時間におっ始めるのかというと、明日仕事から帰ってくる頃には自分のノートが判読不能になって、ヒエログリフの解読作業から始めないといけなくなるから。

セミナーは前半戦と後半戦に分かれていて、前半戦では「大きなラムダ計算」と檜山さんが定義したラムダ計算のインフォーマルスタイルを入り口に、もうちょいフォーマルな(セミフォーマルな)ラムダ計算に変換する訓練と、「絵算」による幾何学的な操作によるラムダ計算の理解が主眼。後半戦はチューリングマシンの停止性問題の解説。

まずは前半戦の方だが、まずは大きなラムダ計算の定義。大きなラムダ計算では、ラムダ式を以下のように記述する。

<x, y | x + y> # 引数を二つ取り、両者を足し合わせる

このときのルールは

  • 自由変数(引数リストにない変数)は使用できない
  • ラムダ式自体を入れ子にすることはできない

の二つ。さらに以下の三つの規則は自明のものとして何の断りもなく使ってしまってよい。

α変換: <x|f(x)> = <y|f(y)> # 束縛変数の名前は取り替え可能
β簡約: <x|f(x)>(a) = f(a)  # ぶっちゃけ関数適用だわな
η変換: <x|f(x)> = f        # これもみたまんま

蛇足ながら Python で書いてみようか。仮に関数の同値性が == 演算子でわかるとして(いやこれは不可能なんだけどね原理的に)、

lambda x: f(x) == lambda y: f(y)
(lambda x: f(x))(a) == f(a)
lambda x: f(x) == f

ちなみにセミナーでちょっと話のでた(ってか俺が話を振った) Io はちゃんとしたラムダ式の記法が無いので、上記のものでいうとβ変換にあたるものを直に記述できない。例えば以下の式の値は何になると思う?

method(x, x + 1)(2)

答えは 3 じゃなくて 2 なんだこれが。とんでもない言語ですね。

話が大幅にずれたので軌道修正しよう。大きなラムダ計算のラムダ式の一例として、次のようなものを考える。

<x, y | 2 * x + y + 3>

これをフォーマルな(小さな)ラムダ式に書き換えるとこうなる。

λx. λy. (A (A (M 2 x) y) 3)

A は加算で M は乗算な。まあ S 式だと思えば。で、関数本体をフォーマルにするとかったるいので、セミフォーマルなラムダ式を使うことにする。

λx. λy. (2 * x + y + 3)

何が違うんじゃと言われるかもしれないけど、フォーマル & セミフォーマルな方は引数の数が常に一つ以下になるよな。というかそれが本来のラムダ式で、インフォーマルな方はλx. λy. λz... というものを引数を複数受け付けて視覚・直観的にわかりやすくしているものと思っていいかも。というか実際のプログラミング言語のラムダ式って、ぶっちゃけ大きなラムダ式だよな普通。例えば Hakell の場合、ラムダ抽象は以下のどっちでもいい。

\x -> \y -> x + y
\ x y -> x + y

こっから先は前のセミナーの内容が頭に入ってないとワケワカメかもしれない。まずは単純な例として、以下のような大きなラムダ式を考える。

f = <x, y| x + y>

こいつのボディ部分をセミフォーマルな形式に変換してみよう。

f^ = <x|λy. (x + y)>

もういっちょ。

f^^ = <|λx. λy. (x + y)>

この ^ 記号は前回のセミナーで出てきた f^E の省略記法ね。それで ^ が増えれば増えるほどセミフォーマルな形式になっていくと。そしてこのλ.という定義に変換していくことを「ラムダ抽象」という。そして前回でてきた E で評価(Eval)すれば、

f(x, y) = E(f^(x), y) = E(E(f^^(), x), y)

という事になる(実際には E の種類は複数あるけど、ここでは省略)。とりあえずラムダ抽象と式の評価についての理解はいいかな。それじゃ今回のセミナーの特徴だったと思う絵算について触れてみる。まずは次の図を見てくれ。

これは何かと言うとラムダ抽象の操作を図にしたもので、左の図は「x, y の二つの引数を f に渡して出力 f(x, y) を得る」様の図で、右の図は「実行エンジン E 経由に f^(x) と y を渡して以下略」な。そしてこの実行エンジンがなにをしくさっているのかが次の図だ。

これは檜山さんが「関数コードの実行エンジンEがズルすることが可能」と書いていた部分にあたると思う。おお、リアルワールドとスノーグローブの世界が地続きになった。

前半戦はこのあたりの事を実際に手を動かしてトレーニングしたりして、それで後は後半戦の停止性問題なわけだが、これ今まで見聞きした停止性問題の説明で一番わかりやすかったかな。以下の記述はいろいろ端折り気味だけど、大体のニュアンスはこんな感じだった。

まず最初に「プログラム」とは何かの定義から。コンピュータにおける一般的なプログラムとは、記憶装置上にロードされて実行され、記憶装置の次の状態を返す(状態遷移させる)ものだとする。いや、一切記憶装置の状態に影響を与えないプログラムもあるだろうけど、それは元の状態と同じ状態がたまたまプログラムの実行結果だったとしておく。

それで記憶装置の状態というのはメモリだろうがハードディスクだろうが単なるバイナリデータ、つまり 0 と 1 の羅列で、これは一意な数値として表現可能だ。そうなるとこの場合のプログラムの動作である「記憶装置の状態を変化させる」というものは、「数値を受け取って数値を返す関数」だと定義してよい。無限ループや例外の場合、記憶装置の状態は不定だ。

ここで停止性問題に切り込もう。ここで「関数のバイナリ表現とその引数を受け取り、その関数が停止するなら true を、無限ループや例外を起こす場合は false を返す」もの凄い関数「G」があると仮定する。

この仮定の元で、以下の関数を考えてみよう。

int f(int x) {
    if (G(x, x)) {
        while (true) {}
    }
    return 0;
}

任意の数値に対して G を呼び、その結果が true であれば無限ループに陥り、そうでなければ 0 を返す関数なのだが、こいつの引数として「コンパイルされてバイナリデータ(=数値)になった f それ自身(f')」を渡したらどうなるかな?

  • G(f', f') が true の場合、 f(f') は停止するので f(f') は停止しない
  • G(f', f') が false の場合、 f(f') は停止しないので f(f') は停止する

明らかにこれはおかしい。つまりこれは仮定が間違っており、つまりは G なんて存在しないということだ。そしてその一方で、このような関数が存在しないということを証明する事ができる。この「我々は決して知ることのできない事があるという事を知ることができ、それはとても不思議な事だ」というニュアンスの言葉が今回のセミナーの結論というか締めの言葉だったわけ。

……で、これと絵算がどう繋がるのか実はセミナーが終わった時点では今ひとつピンと来てなかったんだけど、その後にたけをさんに話を振ってみて返ってきたのが

たぶん、ラムダ抽象(f を f^ にする操作)が入ることでコード(関数)とデータ(値)が同じ整数/バイナリにエンコードできるようになって、その2つが一緒くたに扱えるようになったからパラドックスも発生するようになったってことですかね

という答えで、これと「実行エンジン E のズル」を合わせて考えると、何となく繋がりが見えてきた気がする。どんな観点から見てもスノーグローブとリアルワールドなどの入れ子世界同士がまったく同じ原理で動いている限りは実行エンジン E のズル = 上位層世界との接合が出てきてしまう。それでこのチューリングマシンの停止性問題に出てくるパラドックスというのは自己言及性というかメタ巡回性の問題(数学屋・論理屋じゃないのでこの辺の用語は適当)で、リアルワールドとスノーグローブの区別がつかない(メタ巡回)プログラム実行環境ではプログラムの停止性を汎用的に検出することは不可能(パラドックスに陥る)……何か書いてて怪しくなってきたけど、こんな氷原表現にしかならんなあ。

って、書いてるうちに 03:43 とか無茶苦茶な時間になっちまった。

(21:43)

いろいろ書こうと思ったが、何を書いても陳腐な文面にしかならなかったので今はただ R.I.P. とだけ。

2009-02-21
Sat

(00:07)

さて仕事の方は無茶苦茶な状況になりつつあるのだが、プライベートの方もかなり破綻気味。まず読もうと思って積んじゃってる本が何冊かあって、しかも本社勤務じゃなくて協企に常駐だから仕事をサボって本を読むとかできなくなってるだろ。今までは午前中は完全にサボって本読んでプログラム書いてて(仕事は終わらせてるんだから文句を言われる筋合いは無い)、それを前提にスケジュールを立ててたんでまずこれで破綻一ヶ所。

で、セブンスドラゴン発売までにエトリア冒険記を終えないといけなくて、さらにそのせいで遊べてないゲームが何本かある。とりあえず今のところ購入予定なのは以下の四本。

  • デビルサバイバー
  • FFCC EoT
  • デスティニーリンクス
  • ロックス・クエスト

あとワギャンとかも買うかもしれない。

(14:11)

で、セブンスドラゴンのヒーラーの動画が公開されたわけだが、どうも世界樹のメディックというよりは、蘇生スキルのあるドクトルマグスって感じ? だとすると、現状予定している「ローグ・メイジ・ヒーラー・プリンセス」という編成の不安要素である直接的な打撃力の低さが多少は緩和されるか。

2009-02-22
Sun

(19:09)

カプコンが手を引いたあとに別の会社が引き取ったというろくでもない経緯で発売された「新宿の狼」だけど、プレイ動画を見る限りは何かもの凄いバカゲーっぽい。あいにく俺は PS2 を持っていないのだけど、持っていたらこれは買っている。

しかし適当に無実の一般市民をボコ殴りにして金を巻き上げるとか、車を強奪して人を轢くとか、一体どこの GTA だよ。まあ、リアル警察も点数稼ぎのために適当な理由で捕まえたり、捜査のヘマを誤魔化すために冤罪を起こしたりしてるから、そういう意味じゃリアルと言えなくも……って流石にここまではねえよ。

2009-02-23
Mon

(23:45)

そういや先週あたりから自社ではなくて客先(というかパートナー企業)の方に出向いてるんだけど、ノーネクタイでも上司含めて誰もツッコミを入れてこなかったな。まあ、多分いろいろ諦められているのだろうが。

2009-02-24
Tue

(22:47)

額にある第3の目がアルファケンタウリのビッグブラザーより「OCaml の修行をせよ」との電波を受信したので、とりあえず「入門 OCaml」を購入して OCaml の修行開始。

……と思ったが、標準モジュールに Unicode サポートがないっぽいので(やっぱ使いたいじゃんそんぐらい)、とりあえず extlib を突っ込んでみたんだが(UTF8 サポートだけだが俺はそれしか使わん)、以下のコードのコンパイルが通らなくて参った。

open UTF8;;
print_int (length "あああ");;
print_char '\n';;

調べて見たところ、標準ライブラリでないモジュールについてはコンパイル時に "-I +site-packages/extlib extLib.cmxa" みたいに指定しないといけないんだと。でもこれ、 /usr/lib/ocaml の下にある奴なんだよなあ。そのぐらい勝手に引っ張ってこいやとか思わなくもない。まあ、 C みたいなもんだと思えば腹は立たないが。それと一行コメントに相当する文法が無いのは壮絶に不便。こういうちまちましたプログラムを書いている場合、一行コメントがあった方が遥に便利なんだけどなあ。

2009-02-25
Wed

(19:58)

とりあえず OCaml のコンパイラの基本的な使い方とモジュールの基礎までやってみた。まず OCaml はバイトコードとネイティブコードの二種類の出力形式がある、というかコンパイラが二種類ついてくるが、俺は今のところネイティブの方しか使ってない。バイトコードで出力すると OCaml の対話型インタープリタでロードしていろいろできるが、残念ながらこのインタープリタの操作性は GNU Readline モジュールを使っていないせいで非常に悪い。これはライセンス上の理由で使えないせいのだと言われているけど、今確認したら OCaml って QPL と LGPL のデュアルライセンスになってたぞ。

まあそれはおいといて、まずはコンパイラの使い方だが、基本的には

  1. "ocamlopt -c foo.mli" でシグネチャを先にコンパイル(.mli ファイルを作ってある場合ね)
    • 出力は .cmi ファイル
  2. "ocamlopt -c foo.ml" でソースファイルをコンパイル
    • 出力は .cmx ファイル と .o ファイル
  3. 上記の手順を繰り返す
  4. "ocamlopt foo.cmx bar.cmx..." でリンクして終了
    • デフォルトの実行ファイルの名前は a.out

このとき標準でないライブラリを参照している場合、その都度昨日の日記に書いたようにライブラリを指定してあげること。この辺りはいちいち手でコマンドを打っていられないので、 Makefile(最近は OMake?)でビルドの手順を自動化しておかないとやってられない。あと出力されるファイルの数が結構な数になるけど、それぞれのファイルの意味はちゃんとオフィシャルのリファレンス・ヘルプで確認すること。

いい加減モジュールシステムに移ろう。先に書いておくと、俺は OCaml のモジュールシステムは割合良さそうに思える。まず OCaml のモジュールの基本単位はファイル。ディレクトリはあまり関係なくて、あくまでもファイル。ファイルの名前は特に規定は無いっぽいけど、ファイル名の先頭を小文字にするのが一般的な命名規約らしいのでそれに従うことにしよう。ここでは foo.ml というファイルを作り、以下のようなコードを書いたとする。

let sum x y = x + y;;

この時自動的にファイル名の先頭を大文字にした名前がモジュール名として使用されるので、この場合は Foo モジュールが作られ、その中に sum 関数が定義された状態となる。そのため、もしも次のように書いてしまうと Foo モジュールの中の Foo モジュールという階層ができてしまう。

module Foo =
struct
    let sum x y = x + y;;
end;;

「入門 OCaml」ではモジュールについての説明の頭の方にファイル名とモジュールの関係が出てこなくて、あくまでも対話型インタープリタ上でのコーディングしかされておらず、ファイル名がモジュール名になるとかの話が出てくるのはファンクターの説明が終わったあと。これはあまりいい構成ではないと思うぞ俺は。

ちなみに同じようなことはシグネチャにも言えるので、先の Foo モジュールのシグネチャは以下のように書ける。

val sum : int -> int -> int

ocamlopt -i で .ml ファイルのシグネチャ一覧が出力されるので、それを元に .mli ファイルを作ると楽かもしれない。まあ、全部の関数や型を外部に公開する場合はそもそも .mli ファイルはいらないんだが。

あとさっき「ディレクトリはあんま関係ない」と書いたけど、それについて少し。例えば hoge というディレクトリに fuga.ml というソースコードを置いてあるとする。これが Python なんかだとライブラリのサーチパスから hoge ディレクトリが見える場合、モジュールへのアクセスは hoge.fuga のようになる。それに対して OCaml は fuga.ml のモジュールはあくまでも Fuga であり、そもそもライブラリのサーチパスから hoge ディレクトリが見えているだけではダメ。仮に hoge ディレクトリがライブラリのサーチパス(/usr/lib/ocaml とか)直下にあっても、それはサーチパス上にあることにはならない。

なので明示的に hoge ディレクトリをコンパイルオプションなりなんなりでサーチパスに加え、その上で fuga.cmx をリンクするファイルに加え、それで Fuga モジュールを使うというスタイルになる。とりあえず以下のようなファイル・ディレクトリ構成を考える:

hage.ml
hoge/
    fuga.ml

それぞれのソースファイルの中身はこんな感じ:

(* hage.ml *)
print_int (Fuga.mul 1 2);;

(* fuga.ml *)
let mul x y = x * y;;

この時 hoge.ml をコンパイルするまでの手順は簡単には以下の通り。

$ ocamlopt -c hoge.fuga.ml
$ ocamlopt -I hoge fuga.cmx hage.ml

もしも「Hoge の中の Fuga モジュールという定義にしたい」というのであれば、それはモジュールの include あたりを使えばできる。

モジュールについてはいろいろ面白い機能があるみたいだけど、それについてはまた別の日に。

2009-02-26
Thu

(22:09)

セブンスドラゴン発売まであと一週間なのだが、エトリア冒険記はようやく第5階層が終わったところだ。あと一週間で第6階層を突破して逆鱗マラソンをクリアしてフォレストセルを叩き殺すとかかなり無理臭いけど、まあやるしかないな。

ちなみに今回は開発者の「レベル50でクリアを想定」という言葉通りにクリアできるかどうかやってみたんだが、まあ医術防御なしでもクリアできるっちゃできるんだよな。でもこれ余裕を持って戦うにはレベル50後半は欲しいよなあ。確か世界樹IIも、オーバーロードに挑むころにはレベル50後半だったと思うし。

しかしレベル50かつ普通の装備で第6階層に挑むと、メタルシザースの激怒のはさみでダークハンターが HP の上限の2倍のダメージを受けて即死とかマゾマゾしいバランスになるな。ってかマジでこれどうすんだ。

2009-02-27
Fri

(20:24)

「そういや今月分の給与明細、まだ送られてきてないよな」
同僚
「え? もう送られてきてるけど?」

こういう場合、大抵の場合間違ってるのは俺だ。なので家に帰ってきてからアパートの郵便受けの近くのゴミ箱を漁ってみたら、やはりというか何というか広告の類と一緒に捨ててた。毎度の事だけど、何やってんだ俺。

(21:16)

設計書が毒電波を発する怪文書だったせいで実装が腐敗したプロジェクトなら経験したが、妥当な設計書から壮絶極まる瘴気を放つ実装が放り出されたケースは初めてだ。昨日の時点までは「流石にこれは設計書も解読不能だろ」と踏んでいたけど、発掘した設計書は割とちゃんと書いてあったんだよな。それでこの実装になるか。どんだけフザケた外注使ったんだ、これは。

それで SI 業界にいると「実装はシステム開発全体のほんの一部で重要ではない」って言葉を聞くんだが、だからといって低品質なコードをのさばらせちゃダメだろ。ダメダメな実装は「メンテナンスが困難」「パフォーマンスが悪い」「高いバグ混入率」といった問題を抱えていて、例えばコピペだらけで 3000 行を越えるメソッドの保守とかやりたくないだろ。

大体システムってのは実装して終わりじゃなくて、その後に各種のテストが待ち受けていて、最終的にクライアントに納品して運用しなきゃいけないわけだろ。それで本番で予期せぬ問題が発生したり、新機能の追加要求が出てきたとき、実装が死んでるんで改修に余計なコストがかかるとかどう考えてもおかしいだろ。それで終いにゃメンテナンスが不可能なので全面改定みたいな話が出てきて、一部分でもいいから流用ができないかの調査に俺が投入されて、「おたくのシステム、腐敗どころか白骨化してますよ(意訳)」みたいな報告書が上がってくるわけだ。

それで実装の品質を保証しようとした結果、「Fooクラスのインスタンスを作って、そのインスタンスのbarメソッドに引数 buz を与える」みたいなレベルで記述されるプログラム設計書が作られることになって、大体そういうところは同時に余計な管理ワークが発生して、ただでさえチンカスのような管理ワークが余計チンカスになるんだよ。俺はそういった管理ワークに忙殺された結果、本来やらなければならないコードレビューなどができなくなって、さらには単体テストをまともに実施することすらできなくなって、その単体テストを通してないソースがなぜか納品されてしまい、システムテストで大炎上したという事例を知っている。そのくせこっちで共通処理をライブラリにまとめたりといった工夫をしようとすると、「当初の予定に入っていないクラスの作成は不可」とかいうお達しが来るからわけわからねえ。

結局のところこれらの問題は「言われたままにタイピングするしか能のない類人猿」を雇っていて、さらにそれをプログラマのデフォルト値としている事に起因するので、とにかく普通のコードが書ける奴を雇うしかない。別にもの凄く傑出したプログラマである必要なんて全然なくて、先に出した例だと「コピペだらけで 3000 行を越えるメソッド」とかを書かないと信頼できる程度でいい。

2009-02-28
Sat

(23:52)

エトリア冒険記の方も撮影したスクリーンショットのファイル数が結構な数になってんなあ。今んところ採用してるのは大体 550 枚程度だけど、実際には没になった奴も結構あって、それ含めると 1600 枚程度になるんだよな。そんなに高解像度で撮ってるわけじゃないから、容量的には大したことないんだけど。

あとこれは前にも書いた気がするけど、やっぱ DS に組み込みでスクリーンショットとかゲームのプレイ動画とかを撮影・録画する機能が欲しいよ。