トップ 最新 追記

じじぃの日記、ツッコミ可

Twitter: @jijixi_org
Xbox Live: jijixi

初心者が書いた OCaml 入門
Spotlight tips サイト内リンク集
1970|01|02|
2003|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|11|
2011|05|
2012|01|

2006-05-01 [長年日記]

% [PC][雑談] なんか最近、猫も杓子も SICP ですなあ……

なんか、読んでないと人として終わってるんじゃないかって錯覚に陥いりつつあるぞ(苦笑

よーし、わしもいっちょ勉強してみっかなー Scheme じゃなく OCaml で書いたりとか……と思ったけど、なんだ高いな日本語版。 英語版と倍ほども違うのはどうなんだ (装丁の違いもあるのかもしれないが)。 でも英語版だと、内容の前に言葉の問題で挫折しそうだ...orz

……保留(ダメダメ


2006-05-02 [長年日記]

% [独り言] あー!! ソースはもっとちゃんと整理してー!!

でもそんなこだわり見せてる暇が……

% [Mac] いつからか curl が bus error で落ちる件

おかげで fink のパッケージが更新できない。 なんとなくシステムが 10.4.6 になってからのような気がするんだが……

% otool -L /usr/bin/curl
/usr/bin/curl:
        /usr/lib/libcurl.3.dylib (compatibility version 4.0.0, current version 4.0.0)
        /usr/lib/libssl.0.9.7.dylib (compatibility version 0.9.7, current version 0.9.7)
        /usr/lib/libcrypto.0.9.7.dylib (compatibility version 0.9.7, current version 0.9.7)
        /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.2)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 88.0.0)
% ls -l /usr/bin/curl /usr/lib/libcurl.3.dylib /usr/lib/libssl.0.9.7.dylib \
 /usr/lib/libssl.0.9.7.dylib /usr/lib/libcrypto.0.9.7.dylib /usr/lib/libz.1.2.3.dylib \
 /usr/lib/libSystem.B.dylib
-rwxr-xr-x   1 root  wheel    90108  3 21  2005 /usr/bin/curl
-r-xr-xr-x   1 root  wheel  4379344  4  5 08:15 /usr/lib/libSystem.B.dylib
-rwxr-xr-x   1 root  wheel  1209056  4  5 08:15 /usr/lib/libcrypto.0.9.7.dylib
-rwxr-xr-x   1 root  wheel   201156  4  5 08:15 /usr/lib/libcurl.3.dylib
-rwxr-xr-x   1 root  wheel   267012  4  5 08:15 /usr/lib/libssl.0.9.7.dylib
-rwxr-xr-x   1 root  wheel   267012  4  5 08:15 /usr/lib/libssl.0.9.7.dylib
-rwxr-xr-x   1 root  wheel    72588  4  5 08:16 /usr/lib/libz.1.2.3.dylib

うーん、なにやら実行ファイルだけ古い。

% [Mac] curl が bus error の件 (暫定回避法)

wget がインストールしてあれば、/sw/etc/fink.conf の…

DownloadMethod: curl

となってるところを、

DownloadMethod: wget

にしてやることで回避が可能。 fink 以外で curl を使ってるものは今のところ思いあたらないんで、しばらくこれですごすとしよう。


2006-05-03 [長年日記]

% [game] いまさらながらメテオスを買った

安かったんで (1,980 円)。 でも、ちょっとした息抜きのためにと思って買ったのに、起動回数 5 回で総プレイ時間 7 時間はダメだろ(苦笑

中毒性高すぎるんで危険。


2006-05-05 [長年日記]

% [雑談][Mac] livedoor Reader を試してみたりしてるが…

OmniWeb5.5 が近付いてきたので、Safari から乗り換えるために RSS リーダーをどーしよーかなーと思ったりしたんで、ちょうど話題のやつを試してみてるわけだけど。 でも、初めてまともに使った RSS リーダーが Safari だったせいもあるのかもしれないが、Sarafi とか Firefox の Sage とかローカルで見るタイプの方が好みな気がするのであった。

つーか Safari はフィードの登録を一般的な形式で書き出せるようにしてください。 わしが購読してるのは大した数じゃないから力まかせに手で登録しまくったけど、もっとヘビーに使ってる人は Safari からどこにも移行できないのじゃなかろうか。

ともあれ肝心の livedoor Reader だが。 他のサービスを利用したことが無いんで比較対象が Safari と Sage しか無いんだけど、まあ普通に使いやすいとは思う。 Safari では大して読みそうもないのはノイズになるから登録しないようにしてるんだけど、レートを使えばその辺を気にせずに、適当にフィードを追加していけるような感じなのは良さげ。

ただ Mac だと更新通知が Dashboard Widget なのがちょっと不満。 こういうのは Menu Extra にしてくれないと使いにくい。 Menu Extra 版の Notifier が出たら、乗り換えても良いかなあ。

あと、登録できないフィードがそれなりにあるのが微妙。 この辺は今後に期待だね。


2006-05-06 [長年日記]

% [雑談] 必要ないときにはたくさんあるくせに、いざ必要なときに見つからないもの

それはシリアルケーブル。 5 本も 6 本もあったのに、やつらはいったいどこに行ったんだ。 どうしても見つからないから、結局わざわざ買いにいくはめに...orz

って言うか、シリアルケーブル買いに行ったはずなのに、なぜか帰ってきたときにはテトリス DS も一緒に持ってたりするのが参るよね。 なんでこうなっちゃうかなあ?

% [雑談] カカオ 99% 食った

ちょっwww ゲロマズwww

良いのか、こんな『食い物として成立してない』もの売って(笑)。 もう少し『食える』ものかと思ってたよ。

% [独り言] 愚痴

「そこの処理をやってるのは、このコードです。」と自信満々に寄越したもの (紙でな...orz) を信じてそれに合わせたコーディングしたのに、全然やってること違うじゃねーか、くそぅ。 結局実際に実機のデータをキャプチャして、あーだこーだしなきゃないんだったら、うんざりしながらプリントアウトされたコード読んだわしは何だったんだと小一時間……

本日のツッコミ(全4件) [ツッコミを入れる]

Before...

% jijixi [一緒に買ってきた 72% だったかは普通に食えたんだけどね。 99% は食えたもんじゃなかった(苦笑 罰ゲームに使う..]

% Zapper [85%ぐらいの無かったっけか?]

% jijixi [あるけど 72% が単品の食い物としてギリギリな線て気がする……]


2006-05-07 [長年日記]

% [雑談] SILENT HILL

こんなの作ってたとは。

このページでいくつかビデオクリップが見れるけど、結構おもしろそうかも。 少なくともバイオハザードよりは、まともにホラーしてる感じではある。 裏世界に変わっていくところなんて、かなり凝ってるね。

% [feed][Mac] LivedoorReaderMenu 1.0 for MacOS X (ヒビノアワ)

これはイイ。 さっそく使わせていただこう。

さあ、これで Safari から OmniWeb5.5 に移行する準備はほぼ整ったぞ。 5.5 はまだ文字コード絡みがちゃんとできてないみたいなんで、完全に移行しきれない状況ではあるんだが……(α版だしなあ)

% [feed][Mac] OmniWeb だと livedoor Reader のレート操作が変

これはちょっと困る。 思ったようにレートの設定ができない。

つーかこの操作もキーボードでできるようにしてくれると良いんだけどなあ。 しかたないから、今のところレートをいじるときは他のブラウザ使ってるけど、Omni が直すのが先か livedoor が抜け道用意するのが先か……はてさて。


2006-05-08 [長年日記]

% [独り言] 愚痴々々

parity_even_bit() って関数が (つかマクロだけど) odd の時に真を返すのは非直感的じゃないのか。 even のときに真だと思い込んで浪費した、わしの丸一日を返してくれ...orz

% [独り言] 富豪的プログラミングの敗北

SRAM (スタックに使われます) が 128 byte しか無いのに、32 byte もの大きさの配列なんて使っちゃいけないよね。 関数呼出の時点でグローバル変数 (これも SRAM を使う) がぐだぐだに書き換えられて暴走。 死ねる...orz

OS って偉大だなあ。


2006-05-09 [長年日記]

% [Mac] OmniWeb 5.5 はβを待とう

α版 (sneaky peek 9) は安定はしてるけど文字コード関係の実装がまだダメだし (文字コードの指定が無いページが文字化けする)、livedoor Reader のレートの設定だとか、reddit の like/dislike の設定だとかがうまく動かないんで (JavaScript の実装が甘いのか)、本格的に移行するには時期尚早だと判断した。 ……ので、結局 Safari に戻ったのであったマル。

Safari は Safari でいろいろ不満もあるんだけど……もう慣れたから良いや。 Mac 版の Firefox はいろいろアレだから (フォントの問題とか) メインにする気になれないし、早いとこ OmniWeb がまともに使えるようになってくれると良いなあ。

% [独り言] ようやく終わりが見えてきた

あー疲れた。

% [game] テトリス DS がたまらない件

うん、なんつーの、テトリス自体はどうでも良くて、任天堂のなつかしゲームの音楽とかがバシバシ鳴るのがたまらん。 ドンキーコングとかバルーントリップとか、やりたくてしかたねえぞ。 任天堂はこの時代のゲームを完全移植で出すべきだ。 ついでに、ゲーム&ウォッチの完全移植もな。 GB で出てたのは、ボタンが少なくてつらかった……

ちなみにネット対戦のレートは 5,500 前後。人畜無害。

% [game] なかなか4人集まってくれない件

テトリスのネット対戦の話だけど。 わしはね、4人対戦がやりたいのよね。 でも全然人が集まらんのよね。 寂しいのね。

2人対戦はガチンコすぎてなあ……

つーか、10人対戦やってみたいなあ。 けど、まわりに DS 持ってる人そんなにいないよ。

% [Mac] なんだかわからんが、X Window 絡みが激しく不調

なんかの拍子に CPU フル回転でファンもフル回転でうるせーー...orz

たまに mlterm が巻き込まれて死んだりするんで困る。 しかたないから、しばらく mlterm は使わずに Terminal.app で過ごすことにしてみよう。 昔に比べれば随分軽くなったから、まあ我慢できるだろ。


2006-05-10 [長年日記]

% [feed] livedoor Reader のフォルダ機能はいまいちわしのニーズに合わない

…ので、最初はフォルダ分けする気まんまんだったけど、結局今はレートしか意識してない。 一つのフィードが一つのフォルダにしか所属できないのが、どうにも使いづらいの。

分類好き人間としては、それぞれのフィードを適当な名目のフォルダに登録したくなるわけだけど、こういうのってなかなか一つに決められないじゃない。 日記であって、関数型言語関係であって……みたいなシチュエーションだと、何てフォルダに登録すべきか悩んで悩んで最後にめんどくさくなって放置することになる(苦笑

フォルダというよりは、タグのようなものがあれば良いんじゃないかと思うけど、分類とかはかったるいからレートで大雑把に分けとけば良いや……みたいな感じもしてて、今の状態で十分なのかも知れないとも思うのであった。

% [PC][雑談] データ管理のためのメタファとして『ファイルとフォルダ』は、もう古いのではないか

どうしても『ファイル』がどこか一つの『フォルダ』に収まっているというイメージになってしまうのがいかん。 昔と違ってコンピュータは特別なものじゃなくなったんだから、変に現実のイメージを引きずる必要は無い。 コンピュータはコンピュータならではの管理法をするべきだ。

もう『ファイル』という呼び方はやめてしまおう。『物 (Object)』と呼ぶのだ。 物はいろんなメタ情報を持っていて、ユーザはそれを元に物を呼び出して使う。 もちろん『フォルダ』のようなものをメタ情報としても良いが、複数のフォルダに入れたって良いのである。

それ、なんて WinFS? もしくは Spotlight? それか Google Desktop?

まあ、それらはメタ情報があまりにも広範囲に渡りすぎて漠然としているので、とりあえずメタ情報を『上位の物へのリンク』にしてしまおう。 物はディレクトリの機能とファイルの機能を含有していて、物は他の物へのリンク情報を持つことができる。 そのリンクを手繰っていくことで、目的の物を呼び出すのだ。

それ、なんて実身仮身モデル?

今こそファイルシステム研究者は実身仮身モデルを使った新しいファイルシステムを作るべき。 ちなみに実身仮身モデルってのは、ぶっちゃけて言うとリファレンスカウンタ方式の GC みたいなもんである。 データ本体 (実身) はシステムが密かにどこかで管理して、ユーザは実身への参照 (仮身) を通してアクセスする。 仮身の存在する数がリファレンスカウンタで、仮身がゼロになった時点で実身は削除されるという寸法。

現在の BTRON では実身の ID が 16 bit なので、一つのファイルシステムに実身 (ファイル) が 65535 個しか作れないという制限がある。 これに関して坂村先生は「拡張の必要は無い」という趣旨の発言をしているらしく、BTRON のファンからは非難ごうごうなのだった。

実際のところ今の BTRON は (BTRON2 仕様 OS を実装するような猛者でも現れないかぎり) 終わってるようなものなので、もっと一般的な OS のためのファイルシステムとして誰か作ってくれないもんかのう。 まあ、それを有効に活かすためには、対応したアプリケーションも必要になってくるけども……

% [PC][雑談] ちなみに…

今存在するほとんどのファイルシステムは、上で書いたような『データ本体 (実身) はシステムが密かにどこかで管理して、ユーザは実身への参照 (仮身) を通してアクセスする。仮身の存在する数がリファレンスカウンタで、仮身がゼロになった時点で実身は削除される』という方式ではあるんだよねローレベルでは。

じゃあ何が BTRON と違うかと言うと、結局実身 (ファイル) がディレクトリ (他のファイルへのリンクを保持する存在) としての機能も併せ持っているかどうかだと思われる。 あと、root ディレクトリに相当するものが無いってのもあるけど、それは別に有ったって良いと思うし気にするほどでもないだろう。

そんな感じだから、例えば HFS+ を流用して、リソースフォークにリンク要素を保持するとかって構成で、それに合わせたシェルを作ってやればそれっぽい仕組みは作れそうな気はする。 だからって、そうやって作ったものが実用的になるかっつーと微妙な面もありそうだけど。

% [雑談] ところで、わしがこういうコラムじみたものを書き始めるという状況は…

現実逃避したい気分でまんまんなのだと認識すべきなのである。 実際のところ、あんまり間に受けてマジレスされても困るので釘を刺しておく次第。


2006-05-11 [長年日記]

% [雑談] セブンイレブンのたこ焼きパン

予想の斜め上を行く『たこ焼き』っぷり(笑

丸っこい形で上にはかつおぶしに青ノリ、なるほどこれで中にタコでも入ってるんですね?…… と思ったのに、中から出てきたものは……

た・こ・や・き

マトリョーシカかよ。


2006-05-13 [長年日記]

% [雑談] エウレカセブン

GyaO で 29 話までやってるのを見た。 本放送時は結局一回も見れなかったのよね。 つーか日曜の朝なんて寝てるもんでしょ普通。 あんまりじっくり見てる暇無かったんで、ながら見だったんだけど評判どおりおもしろかった。

それにしても想像してたのと違って、すごく王道な展開なんだね。 メカの設定とか世界観なんかは『新感覚』と言えそうではあるけど、話の流れはいろんな意味でお約束の連続と言うか。 まあ、これからぶっとんだ展開するって可能性も無いとは言えないが。 つーかこれ、何話まであるんだろ。

ともあれ、素材がありふれてても、料理のしかたはうまいのでそれはそれで良いんだと思う。 少なくとも、似たような素材を使った某種なんかよりはおもしろいのは間違いない。 レイ・チャールズ夫妻絡みの話とか泣けたね。 某砂漠の虎では泣かなかったけど :-p

ところで GyaO は残りの分も配信してくれるんだろうか。

% [雑談] 涼宮ハルヒの憂鬱

ついでだから、もひとつアニメネタ。 電撃大王とか買ってるから原作の名前だけは見かけたことがあって、たまたま一回目の放送のときに新聞のテレビ欄で見かけたので試しに見てみたら…… 度肝を抜かれた(笑

あ・り・え・な・い

って言うか原作知らない人にとっては、最後まで「本当に今見てるものが『涼宮 (以下略』という番組なのか?」という疑問を払拭できなかったのではなかろうか。 わしはできなかった。

んで、その時点では「ふーん、ぶっとんだことするなあ」くらいにしか思ってなくて、次からは見てなかったんだけど、五回目のときにたまたま放送時間に起きてたんで、話題になってるのもあるしもう一度見てみた。…… 引っくりかえった(笑

普通に学園物なんだと思ってたら、なにこのとんでも SF?

実は第一話ってこれの伏線かよ!!みたいな。 「素人制作らしさが出てる、すげえぐだぐだな設定だなw」とか思ってたら、本編が素でそういう設定だなんておかしすぎる(笑

それから気になりだして調べてみたら YouTube で過去の話を見れるらしいんで全部見た。 無茶苦茶だな、良い意味で(苦笑)。 まあ、これはアニメ化してる連中がスゴイせいで、原作自体はそれほどおもしろそうにも思えないんだけど、とにもかくにもアニメ版はおもしろいと思う。 あんまりマジメに見てはいけない作品だとは思うけど。 なんつーかいろいろ不条理さがたまらん(笑

ちなみに北海道では放送が月曜の深夜 26:00 とかだったりするので見るのがつらい。 しかし実は月曜の午前中のうちに YouTube にアップされてたりするので、放送前に見れちゃうのであった。 おかげで先週分は月曜の昼に見た。


2006-05-14 [長年日記]

% [OCaml] OCaml の複素数計算

ヒビルテを読んで気になったんで、OCaml でもやってみた。 Complex モジュールには i はあるけど pi や e が無い。 って言うか Complex どころか他のモジュールにも見当たらない。 e はともかく pi も無いのにはびっくりしつつも、Hugs の定義をパクってでっちあげ。

% ocaml
        Objective Caml version 3.09.2

# open Complex;;

# let pi = polar (4. *. atan 1.) 0.;;
val pi : Complex.t = {re = 3.14159265358979312; im = 0.}

# let e = exp one;;                  
val e : Complex.t = {re = 2.71828182845904509; im = 0.}

# pow e (mul i pi);;
- : Complex.t = {re = -1.; im = 1.22464679914735321e-16}

# exp (mul i pi);;
- : Complex.t = {re = -1.; im = 1.22464679914735321e-16}

# log (polar (-1.) 0.);;
- : Complex.t = {re = 0.; im = -3.14159265358979312}

他の言語に比べると、なんてめんどくさいんだ… って感じだけど、逆にそのことに安心感を感じたりするわしはすっかり OCaml に毒されてるってことだろうか(苦笑

% [OCaml] かぶった

mmatsuoka さんとこでも複素数の話をやってた模様。 でも、アプローチが随分違うので、これはこれで良いのではないかと(笑

π が用意されてないのは、用途や分野によって使用する近似値が違ったりするみたいなので、その都度事情にあわせて定義しなさいという事だと好意的に解釈してみたり。(参考-Wikipedia: 円周率の歴史, 円周率)

% [OCaml] さらにかぶった

向井さんとこでも複素数。 ちょっとびっくりしたのが log -1 の結果。

# log { re = -1.; im = 0. };;
- : Complex.t = {re = 0.; im = 3.14159265358979312}

わしのやった方法だと…

# log (polar (-1.) 0.);;
- : Complex.t = {re = 0.; im = -3.14159265358979312}

こうなんだよね。 同じことやってるように思えるのに何で? と思ったら…

# polar (-1.) 0.;;
- : Complex.t = {re = -1.; im = -0.}

こっちは虚数部が -0 になってた。 単に実数から複素数作るために polar 使うのが間違ってるのかな。 よくわかってないで使ってるしなあ(苦笑

% [OCaml][雑談] OCaml のグッタリポイント

上のネタで向井さんも書いてたけど、コメントが (* ~ *) なところはたしかにグッタリ。

ただ、コメントに関してはそのことよりも一行コメントが無いことの方が困る。 まあ、C と違ってネスト可能なんで、本格的に困ることは無いんだけど、やっぱ手軽にちょこっとコメントアウトできる方法が有るのと無いのとでは結構精神的に違いがあると思われ。

% [OCaml][雑談] open したくない人はやっぱりファクトリ関数を定義するのが良いんだろうなあ (グッタリポイントその2)

上記の Complex みたいなモジュールを使う場合、open を使わないといろいろと面倒が多い。 つーか、面倒はともかく例えばレコードを作るときなんか非常に気持ち悪いもんだ。

# let pi = { re = 3.14; im = 0. };;
Unbound record field label re

# let pi : Complex.t = { re = 3.14; im = 0. };;
Unbound record field label re

# let pi = { Complex.re = 3.14; im = 0. };;
val pi : Complex.t = {Complex.re = 3.14; Complex.im = 0.}

なんとかならんもんか、これ。 結局、レコードを素のまま扱うなんてダセーよ… ってことになって、レコードを作る関数を作るはめになる。

# let complex re im = { Complex.re = re; im = im };;
val complex : float -> float -> Complex.t = <fun>

# complex 3.14 0. ;;
- : Complex.t = {Complex.re = 3.14; Complex.im = 0.}

微妙に敗北感を感じたりもするけど、まあ「ちゅーしょーか、じゅーよー」と呪文を唱えて飲み込むのが良かろうて。

% [OCaml] OCaml の有理数

なんとなく Complex をやったら、こっちもやらなきゃないような気がして。

Rational number を扱うには Num モジュールを使う。 Num モジュールは組み込みじゃないので、ライブラリをリンクしてやる必要がある。 ライブラリの名前は num.cma じゃなく nums.cma なので注意。

対話環境で試すときは ocaml コマンドの引数に nums.cma を指定してやるか、#load でロードする。

% ocaml nums.cma

(もしくは)

% ocaml
# #load "nums.cma";;

ただ、これだと Num モジュールに対応したプリティプリンタが無いのでちょっと不便。

# Num.num_of_string "1/2";;
- : Num.num = Ratio <abstr>

GODI を使ってると知らないうちに num_top.cma ってのがインストールされてるので、これも使うと吉。 というか、topfind を使って #require "num" すると、勝手に一緒にロードされるけど。

# #use "topfind";;
# #require "num";;
/usr/local/godi/lib/ocaml/std-lib/nums.cma: loaded
/usr/local/godi/lib/ocaml/pkg-lib/num-top: added to search path
/usr/local/godi/lib/ocaml/pkg-lib/num-top/num_top.cma: loaded
/usr/local/godi/lib/ocaml/pkg-lib/num: added to search path

この状態だと、Num.num の値が読める形で表示される。

# open Num;;           
# num_of_string "1/2";;
- : Num.num = <num 1/2>

num_top.cma が無いときは Num.string_of_num で可視化すると良い。

# let p = string_of_num;;
val p : Num.num -> string = <fun>
# p (num_of_string "1/2");;
- : string = "1/2"

Num.num の定義は、

type num =
| Int of int
| Big_int of Big_int.big_int
| Ratio of Ratio.ratio

のようになっていて、実のところ Ratio モジュールってのを単体で使うことも可能ではあるんだけど、マニュアルに載ってないくらいだから、わりと裏技の部類なんじゃないかと思う。 まあ、使ってもややこしいだけなんで、素直に Num を使っておくべき。 ちなみに同様の隠しモジュールとして Nat なんてのもあるね。 natural number のことらしい。

Num モジュールは基本的には open して使うように作られているっぽい。 演算子は通常のもののお尻に / を付けたもの。 関数は _num を付けたもの。 って感じで名前が付いている。

あとはまあ、マニュアル見ればわかるわ。 もう眠い (投げやり)。

ちょっと変わったアイテムとしては、approx_num_fix と approx_num_exp ってのがあるね。

# let half = (Int 1) // (Int 2);;
val half : Num.num = <num 1/2>
# approx_num_fix 3 half;;
- : string = "+0.500"
# approx_num_exp 3 half;;
- : string = "+0.500e0"

こんな感じのもの。 あと、rational の計算方法を制御する Arith_status ってモジュールもあるけど、なんかよくわからない。

float_of_num があって、num_of_float が無い辺りが浮動小数点数の限界を感じさせるよね。(……させるか?)

本日のツッコミ(全1件) [ツッコミを入れる]

% soutaro [私はいつもモジュール名から書いてますよw ただ、例えばAbc.tの値にabcとか名前を付けておくと、f abc.Ab..]


2006-05-15 [長年日記]

% [OCaml][雑談] レコード型のぐったりさ加減

昨日の soutaro さんのツッコミは、OCaml で open を使わずに他のモジュールで定義されたレコード型を使おうとして四苦八苦したことのある人じゃないと意味がわからないかも知れないと思ったので、ネタバラシをしてみる。

さて、soutaro さんが示した、『f abc.Abc.xyz』という例は一体ナニモノかと言う話だが。 昨日の Complex モジュールを使ってテストしてみよう。

# let pi = { Complex.re = 3.14; im = 0. };;
val pi : Complex.t = {Complex.re = 3.14; Complex.im = 0.}

昨日はここまでしか書かなかったが、この pi の各フィールドにアクセスする場合を考えてみると知らない人は見事にハマる。 open Complex はしていない。

# pi.re;;
Unbound record field label re

ね、こうなる。 多分、大抵の人はこの瞬間唖然とするんではなかろうか。 わしはした。 この場合、正しい書き方はこうだ。

# pi.Complex.re;;
- : float = 3.14

もう気持ち悪すぎ。 わしもどっちかと言うと open はあまりしたくない方なので、この事実を知った時点でほとんどレコードは使う気無くしたね(苦笑

ちなみにオブジェクトであれば……

# module M = struct             
    class complex re im = object
      method re : float = re    
      method im : float = im    
    end
  end;;
module M :
  sig
    class complex :
      float -> float -> object method im : float method re : float end
  end
# let pi = new M.complex 3.14 0.;;
val pi : M.complex = <obj>
# pi#re;;
- : float = 3.14

このように大丈夫。 定義が多少めんどくさいことをのぞけば、レコードよりオブジェクトの方が使いやすい。

他にレコードのグッタリな点と言えば、フィールド名の名前空間がモジュール内で共有されていることだ。 つまり、同じフィールド名を持つレコード型は、同一のモジュールに存在できない。 これのせいで、open を使うスタイルでもやっぱりハマりどころが存在する。

# type hoge = { re : string; num : int };;
type hoge = { re : string; num : int; }
# let h = { re = "fuga"; num = 1 };;
val h : hoge = {re = "fuga"; num = 1}

こんなことしてたとしよう。 ここで、うっかり Complex を open したりしてしまうとひどいことになる。

# open Complex;;
# let h2 = { re = "foo"; num = 2 };;
This expression has type string but is here used with type float

hoge をもう一度定義しなおさないかぎり、hoge 型の値を作ることはできない。 それどころか……

# h.re;;
This expression has type hoge but is here used with type Complex.t

h の各要素にもアクセスできない (あらかじめアクセサを書いておけば別だけど)。 こういうの見ると、OCaml には自分が属するモジュールを指定する文法が必要だと思うんだけどねえ。 それがあれば、open Complex したあとも hoge 型が使えるんだけど。

ともあれ、レコード型は罠が多すぎると思うので、ライブラリを作るときは隠蔽するのが良心的だと思う。 レコード型を直接使わせるような設計だと、ユーザに余計な負担を強いることになる可能性が高いので。 ファクトリとアクセサをあらかじめ作っておけば、型定義が上書きされてしまっても、それらの関数が残ってさえいればそのまま使うことができる。

ちなみにヴァリアント型にも似たような問題がある。

# #use "topfind";;
# #require "num";;

# type foo = Int of string | Float of string ;;
type foo = Int of string | Float of string

# open Num;;

# let bar : foo = Int "1";;
This expression has type Num.num but is here used with type foo

これも自分自身のモジュールを指定できれば回避できるんだけどねえ。 それさえできれば、もう少し気軽に open を使えるようになるのに。


2006-05-18 [長年日記]

% [雑談] 現地で欧州チャンピオンズリーグ観戦 (ワラタ2ッキ)

一瞬意味わかんなかったけど、じわっと来た(笑

ヒント:時間


2006-05-20 [長年日記]

% [雑談] まあ、一応宣言しておくと

ここにセキュリティ関係のネタは無いですよ(苦笑


2006-05-21 [長年日記]

% [OCaml][雑談] レコード型をもう少しなんとかしてくれるなら……

OCamlのレコード型をめぐって』(欝っぽい日記) を読んで思ったことをつらつらと。

なんか自分ではうまく文章にできなくてもどかしかったところを、スパッと切ってくれた印象。

問題はむしろ、「.」がレコードのフィールドにアクセスするという別の意味を持っていること。

それだ!! わしが OCaml のレコード型に関してどうしても許せない違和感を感じてるのは、たぶんこの部分なんだと思った。

この前の例で行くと、

# let pi = { Complex.re = 3.14; im = 0. };;
val pi : Complex.t = {Complex.re = 3.14; Complex.im = 0.}

これはまだ許せるわけですよ。 もう少しかっこいい書き方はできないものかとは思うけど、モジュール名→ ドット→ (識別子|型名) というお作法(?)が守られてるから、まあ納得できる範囲。 でもね、

# pi.Complex.re;;
- : float = 3.14

これはもう何が何だかわかんない。 もし pi が他のモジュールで定義されてたらどうすんですか。

# Math.pi.Complex.re;;

とか書くんですか。 ほんとわけがわかりません。 もしここで、フィールドアクセスが別の記号だったら…

# Math.pi#Copmlex.re;;

ためしにオブジェクトと同じ『#』を使ってみたけど、束縛名である pi とフィールド名である re の区別がはっきりする。 これなら、気持ち悪さは同程度だけど、なんとなく許せるような気がしてくる。 少なくとも、ぱっと見の混乱度は随分減ると思うんだけど……

本日のツッコミ(全2件) [ツッコミを入れる]

% yoriyuki [Emacsでcaml-modeを使うとモジュール名は色がつくので、個人的にはそんなに違和感はないです。(目が見えない..]

% jijixi [個人的には、色が付いていようがいまいが気持ち悪いです…… 読みづらいとか、わかりづらいとか、じゃなく、意味はわかるけ..]


2006-05-22 [長年日記]

% [雑談] 今日のむだづかい

思わず形だけで…… これ

パッシブスピーカーなんて、どうせ使いもんにならんから、たたんだ状態で飾っとけば良いやと思ってたんだけど (注:わしは丸いものが好き) 予想に反してわりとまともな音が出る。 いやぁ、バカにできないね。

% [OCaml] Bigarray モジュール

OCamlの配列のサイズ制限』(sumiiの日記) より。

「何でOCamlの配列は要素がたったの4M個までしか駄目なの?」という質問。

全然知らなかった。 って言うか、そんな大きな配列が必要になる人って少数派だよなーとか思ったり。 少なくともわしは 4M 個も使えれば死ぬまで困らないような気がするけど、それなりに気になったんで「そういや Bigarray とかってモジュールがあったと思ったけど、あれじゃダメなの?」と思って調べてみた。

Big arrays can only contain integers and floating-point numbers,

[The Objective Caml system release 3.09より引用]

な、なんだって〜!?

数値しか要素にできないのか。 それはなんとも微妙な…… でも、巨大な配列が必要になるシチュエーションって大概数値計算じゃないかなっていう気もするし、良いのかしら。 よくわからん。

ともあれ、せっかくだから使ってみる。

% ocaml bigarray.cma
# open Bigarray;;

Bigarray モジュールには、さらに Genarray, Array1, Array2, Array3 というサブモジュールがある。 1,2,3 てやつは、それぞれ 1 次元、2 次元、3 次元ということらしい。 んで、Genarray は 1,2,3 を含めた多次元配列。

ちなみに、

Big arrays are not limited in size,

などと言いつつも、インデックスの型が int なので、各次元の要素数は int の範囲に制限されるっぽい。 いや、それでも十分果てしないとは思うが。

さて、では配列を作って値を読み書きしてみよう。

# let a = Genarray.create complex64 c_layout [|10;10;10|];;
val a :
  (Complex.t, Bigarray.complex64_elt, Bigarray.c_layout) Bigarray.Genarray.t =
  <abstr>

# Genarray.set a [|5;2;3|] { Complex.re = 3.14; im = 0.0 };; 
- : unit = ()

# Genarray.get a [|5;2;3|];;
- : Complex.t = {Complex.re = 3.14; Complex.im = 0.}

各次元の要素が 10 ずつの三次元配列を作って、a[5][2][3] の位置に値をセットして、それを読み出してみた。 一瞬、

# let a = Genarray.create complex64 c_layout [|max_int|];;

とかやってみようかと思ったんだけど、かったるいことになりそうだったから止めた(苦笑

メモリが少ない環境で巨大な配列を使うときには、map_file という関数を使うことでメモリの代わりにファイルを使えるみたい。

# let fd = Unix.openfile "Desktop/temp" [Unix.O_RDWR;Unix.O_CREAT] 0o640;;
val fd : Unix.file_descr = <abstr>

# let a = Genarray.map_file fd int c_layout true [|max_int|];;          
Exception: Sys_error "Cannot allocate memory".

うご…… ハードディスク食いつぶされますた...orz

# let a = Genarray.map_file fd int c_layout true [|10;10;10|];;
val a : (int, Bigarray.int_elt, Bigarray.c_layout) Bigarray.Genarray.t =
  <abstr>

これくらいなら大丈夫ですた。 ともかく、メモリもディスクもアホほど積んだマシンでやるべきです。

どうせだから、ファイルの中身がどうなってるかも見てみっかな。

# let fd = Unix.openfile "Desktop/temp" [Unix.O_RDWR;Unix.O_CREAT] 0o640;;
val fd : Unix.file_descr = <abstr>

# let a = Genarray.map_file fd int c_layout true [|10|];;
val a : (int, Bigarray.int_elt, Bigarray.c_layout) Bigarray.Genarray.t =
  <abstr>

# List.iter (fun i -> Genarray.set a [|i|] i) [0;1;2;3;4;5;6;7;8;9];;
- : unit = ()

とかやっといて…

% xxd Desktop/temp
0000000: 0000 0000 0000 0001 0000 0002 0000 0003  ................
0000010: 0000 0004 0000 0005 0000 0006 0000 0007  ................
0000020: 0000 0008 0000 0009                      ........

うーん、一次元だとあんまおもしろくないかな。

# let a = Genarray.map_file fd int c_layout true [|10;10|];;         
val a : (int, Bigarray.int_elt, Bigarray.c_layout) Bigarray.Genarray.t =
  <abstr>

# let l = [0;1;2;3;4;5;6;7;8;9] in
  List.iter (fun i -> 
    List.iter (fun j ->
      Genarray.set a [|i;j|] (i+j)) l) l;;
- : unit = ()

うわ、ひでえ書き方(苦笑

% xxd Desktop/temp
0000000: 0000 0000 0000 0001 0000 0002 0000 0003  ................
0000010: 0000 0004 0000 0005 0000 0006 0000 0007  ................
0000020: 0000 0008 0000 0009 0000 0001 0000 0002  ................
0000030: 0000 0003 0000 0004 0000 0005 0000 0006  ................
0000040: 0000 0007 0000 0008 0000 0009 0000 000a  ................
0000050: 0000 0002 0000 0003 0000 0004 0000 0005  ................
0000060: 0000 0006 0000 0007 0000 0008 0000 0009  ................
0000070: 0000 000a 0000 000b 0000 0003 0000 0004  ................
0000080: 0000 0005 0000 0006 0000 0007 0000 0008  ................
0000090: 0000 0009 0000 000a 0000 000b 0000 000c  ................
00000a0: 0000 0004 0000 0005 0000 0006 0000 0007  ................
00000b0: 0000 0008 0000 0009 0000 000a 0000 000b  ................
00000c0: 0000 000c 0000 000d 0000 0005 0000 0006  ................
00000d0: 0000 0007 0000 0008 0000 0009 0000 000a  ................
00000e0: 0000 000b 0000 000c 0000 000d 0000 000e  ................
00000f0: 0000 0006 0000 0007 0000 0008 0000 0009  ................
0000100: 0000 000a 0000 000b 0000 000c 0000 000d  ................
0000110: 0000 000e 0000 000f 0000 0007 0000 0008  ................
0000120: 0000 0009 0000 000a 0000 000b 0000 000c  ................
0000130: 0000 000d 0000 000e 0000 000f 0000 0010  ................
0000140: 0000 0008 0000 0009 0000 000a 0000 000b  ................
0000150: 0000 000c 0000 000d 0000 000e 0000 000f  ................
0000160: 0000 0010 0000 0011 0000 0009 0000 000a  ................
0000170: 0000 000b 0000 000c 0000 000d 0000 000e  ................
0000180: 0000 000f 0000 0010 0000 0011 0000 0012  ................

あー、まあ普通やね。 要素の型はどうやって判別するんだろう? と思ったけど、これって保存のためのシリアライズじゃなくて、単にファイルをメモリ代わりに使ってるだけなので、あとから読み込むことは考慮されてないのかな。 実際、ファイルを読んで配列に復元するような関数は見当たらないし。 もしかしたら、Marshal モジュールが使えるかも知れないけど、そもそもあれはタイプセーフじゃないし、結局型情報は自前でごにょごにょやらなきゃないんだろうなあ……

とまあ、そんなこんなで、なんとなく試してみたけど、やっぱりわしには縁が無さそうなモジュールでありましたとさマル。

% [雑談] 今週のハルヒ

うーん、先週の話は結局『ハルヒのために、誰かが事件を提供してるんだよ』っつー伏線だったのかね。 実際そのおかげか今週はすんなりと、うさんくささを感じることができたし(笑


2006-05-24 [長年日記]

% [雑談] 何日かぶりにジーグスレ見たら今話題のアレが……

95。 ぼくらのジーグヘッドが何か怖いものに!!(笑


2006-05-26 [長年日記]

% [Mac] OmniWeb 5.5 sneaky peek 12

ようやく文字コードの自動認識が効くようになったんで、日常的に困ることはほとんど無くなった。 livedoor Reader でレートの設定がうまくできない件は、微妙に直りつつある気がする。 reddit で矢印をクリックしたときの結果が反映されないのは、ちと困る。

ベータ版には、もう一息ってところか。

% [game] New スーパーマリオブラザーズ

くそ、わしは落ちて死ぬゲームは嫌いなんだよ。 昔っから 2D のマリオとは相性が悪いんだよ。 あーちきしょう、でもおもしれえよ、ああ、おもしろいですよー!!

・・・ってことで、とりあえずクリアしてしまったのであった。 昨日というか今日の朝方までやってたしね。 アホかわしは。中学生かっての...orz

ともあれ、まだまだ噛み残した部分はたくさんあるので、あとはまったりやろう(疲

ちなみにクリア後の特典は、マップ上でいつでもセーブできるようになることと、ルイージが使えるようになること。 ルイージとマリオに性能の違いがあるかどうかは知らん。 あと、集めたスターを使って壁紙が買えるようになってるみたい。 スター 20 個も使うわりに、効果は地味な気がするけど。

% [FreeBSD] 6.1R にアップグレード

した。 何かをサービスしてるようなマシンじゃないんで、CD でブートしてアップグレードして、シングルユーザモードで mergemaster して終了だけども。 Ports は current 使ってるから、特にすること無し。

アップグレードインストールのときの注意点と言えば、ディストリビューションの選択時に X を入れないってことやね。 昔はたぶん大丈夫だったんだろうけど、今は X を packeage で入れるようになってるから、インストールに失敗する。 X 無しでインストールして、後で portupgrade するのが吉。

本日のツッコミ(全1件) [ツッコミを入れる]

% グチこぼし [ルイージはクリアしなくても使えます。 マリオとの性能の違いはないはずです。]


2006-05-28 [長年日記]

% [Mac][vim] 7.0 を入れた

fink の vim がいつまでたっても 7.0 にならないんで、自前でビルド。 つーか、fink の vim 担当はやる気が無いのか、いまだに 6.4 にすらなってないわけだが……

vim なんて特に何事もなくビルドできるものだから、fink の info ファイル書いて送りつけちゃろうかとも思ったけど、どうせ放置されるのがオチだから止めた。 ちなみに、例の mblen 問題は対応が vim 側で取り込まれたようなので、もう気にしなくて良い。

7.0 の目玉と言えば Keyword Completion の強化だと思われ、今まででも補完機能は十分便利だったんだけど、今度は激しく便利になったと言うか、もうほんとに IDE とかいらないよ。 一度慣れると、もう 6.x 系には戻れないなあ、これは。

あと、カーソル位置のカッコに対応するカッコがリアルタイムにハイライト表示されるようになってたり。 これは地味だけど大きい。


2006-05-29 [長年日記]

% [OCaml] 多相型の罠

罠っつーと大袈裟かもしれないけど、こんなこともあるよという話。

暇だったんで、久しぶりに以前のモナドもどきをちょこっといじってたのである。 まあなんつーか、まじめに使うことを考えずに作ったものなせいで、Monad.invoke のたびに (たとえすでに評価済みであっても) いちいち全部評価しなおすというパフォーマンス上の問題があったんで、それをちょっくら直してやろうかと思って。 どっちみち実用に供するつもりもないんだけどね(苦笑

てことで、元々の内部表現は unit -> 'a な関数だったものを、その関数と関数を評価した際のキャッシュを持つレコードに変えた。 具体的にはこんな感じ。

type 'a t = Monad of (unit -> 'a)

module Utils = struct
   let make proc arg = Monad (fun () -> proc arg)
   let wrap arg = Monad (fun () -> arg)
   let wrap_lazy arg = make (fun x -> Lazy.force x) arg
   let invoke m =
      let Monad f = m in f ()
   let through arg = make (fun x -> invoke (Lazy.force x)) arg
end

これを…

type 'a internal_record = { proc : unit -> 'a; mutable value : 'a option }
type 'a t = Monad of 'a internal_record

module Utils = struct
   let make proc arg = Monad { proc = (fun () -> proc arg); value = None }
   let wrap arg = Monad { proc = (fun () -> arg); value = None }
   let wrap_lazy arg = make (fun x -> Lazy.force x) arg
   let invoke m =
      let Monad r = m in
      match r.value with
      | Some a -> a
      | None ->
           let tmp = r.proc () in
           r.value <- Some tmp;
           tmp
   let through arg = make (fun x -> invoke (Lazy.force x)) arg
end

こんな感じに直したわけ。 ここで、Utils モジュールの各関数は同じ型になるので、

module Utils :
  sig
    val make : ('a -> 'b) -> 'a -> 'b t
    val wrap : 'a -> 'a t
    val wrap_lazy : 'a Lazy.t -> 'a t
    val invoke : 'a t -> 'a
    val through : 'a t Lazy.t -> 'a t
  end

これで終了だと思ったんだけど、monadList.ml でコンパイルエラーに遭遇した。 ↓ こんな感じ。

ocamlc -c monadList.ml
File "monadList.ml", line 254, characters 20-24:
This expression has type 'a -> 'b Monad.t but is here used with type
  'a -> int

こういうエラーが出たときに、何が原因なのか把握するにはある程度慣れが必要な気がする。 ぶっちゃけて言うと、これは『多相値のつもりで使ってる値が、実際には単相値になっている』場合の典型的なパターンだと思う。 でも、インターフェイスが変わったわけでもないのに何故? と、しばらく悩んでしまった。 結論から言うと、monadList.ml には以下のような部分があって、

type 'a cell = Null | Pair of 'a * 'a t
and 'a t = 'a cell Monad.t

include Monad.Utils

let null_list : 'a t = wrap Null

この null_list の型が修正前は 'a t だったのに、修正後は '_a t になっているのであった。 そんなわけで、null_list の定義を、

let null_list () : 'a t = wrap Null

… と、関数型にして対処した。 あと、null_list を使ってるところは (null_list ()) に置換ね。

ところで話がそれるけど、この前さんざんレコード型をけなしておいて今回レコード使ってるのは、こういう内部表現に使うには手軽だと思うからで、ライブラリの公開インターフェイスとして使うのはやっぱりキライ。

さて、話を戻して。 今回の場合、ライブラリ側 (monad.ml) もユーザ側 (monadList.ml) もいじるのは同じ人間だったから良かったけど、もしこれが別の人間がいじるという場合には果たしてこのような問題は『どちらが』悪いのだろうか? というかどちらがより『気をつかうべき』なんだろうか?

ライブラリ側では内部表現をいじったとは言え、公開される関数の型は変わっていない。 実際、修正前の null_list が 'a t という型でいられたのは、Monad.t の内部表現が『たまたま』関数型だったからにすぎなくて、もしそうでなければ、当然 null_list は '_a t であったはずなのだ。 その『たまたま』を利用されてることまで考慮するのは厳しい気はする。

ということはやっぱりユーザ側が悪いのだろうか。 でも、『たまたま』内部表現が関数型なおかげで (null_list ()) とか書かなきゃならないところを単に null_list と書けるようにできたわけだけど、そうしたくなる気持ちもわかるんだよな。 だって、まさにわしがそういう気持ちで null_list の定義を書いたわけで。 まあ、たしかにこういうのはバッドノウハウ的なんだとは思うけど。

結局、ユーザ側は多相値を定数的に使いたいときには常に関数で返すようにしておくのが無難な線ではあるんだが、それにしても多相値のつもりで使ってるのが実際には単相値になってるって状態を、もっとわかりやすく検知する方法はあって良いと思うなあ。 わしも今まで何度もそういう場面にぶつかって、どんなエラーが出るかを体で覚えてたから今回の件もわりとすぐに対処できたけど、慣れないうちは何が起こってるのかわけわかんないと思うのよね。 つーか実際、以前はわけわかんなかったよ。

どうするのがより良いのかはわかんないけど、何とかならんかなあと思う問題ではあるんじゃないかと感じるできごとであった。

おまけ: 使う人はいないだろうけど、一応今回のバージョン置いとく。→ monad_modoki_20060529.zip


2006-05-31 [長年日記]

% [vim][雑談] vim -y を終了する方法

某所のネタを読んで試してみたは良いが、終了できなくて往生してる人のための tips。 gvim -y ならメニューで終了したり、ウィンドウごと殺したりで良いんだけどね。 いや、vim -y も端末ごと殺した人はたくさんいそうだけど(苦笑

もったいぶっても仕方ないんで、さくっと書くと、

i → Ctrl+l

と押すとコマンドモードに入れるので、あとは :q! とか適当に。 コマンドモードに入るために、必ずゴミが入力されるのがウザス(笑

(追記)

ツッコミが入ったので追記というか訂正。

Ctrl+l

だけでコマンドモードに入れるみたい。 もともとこのネタを調べたのは随分前なので、何でこう憶えてたのかは思い出せないんだけど。 ともあれ、これならそれなりに使い物になるねえ。 まあ使わんけど(苦笑

本日のツッコミ(全2件) [ツッコミを入れる]

% にく [<C-l>だけでいけるような気が]

% jijixi [あら、ほんとですね。 何か勘違いしてたみたいです。]


トップ 最新 追記

日記ってのは本来、自分で読み返すためにあるもんだよなあ……
もしくは有名人になったら死後に本になったりとかか?

RSS はこちら

jijixi at azito.com