Twitter: @jijixi_org
Xbox Live: jijixi
この前 FreeBSD のインストールに失敗した旧 iMac には Debian/Sarge を入れた。 こいつはメモリが 512MB あるんで、奮発して GNOME とかも入れてみた。
それは良いんだけど、音が鳴らねえ。 PPC 版はデフォルトのカーネルが 2.6 だから、たぶん音も ALSA で出すんだと思うけど、ALSA はよくわからん。 つーか、全体的には鳴らないけど、Totem 動画プレイヤーとかいうやつでは鳴ってたり謎。 でも Totem で DVD を再生すると鬼のように重くて見るに耐えないから、じゃあ vlc を…と思うと音が鳴らん。 OSS 互換モジュールを有効にすれば良いのかねえ。 Linux の音関係はややこしくていかん。 FreeBSD なら一発なのに……
あと Epiphany(と言うか Mozilla)が未だに IM の切り替えに対応してないのがムカツク。 環境変数で強制する方法があったはずだけど忘れちゃったよ、もう。 一度 gtkim (だっけ?)だけで完結する環境(XIM を使わない環境)を作ってみたかったんだが(普通の人に使わせるような用途でね)、これじゃダメじゃんか。
WinME をリカバリした後放置してた LOOX にも Sarge を入れた(Win は残しつつ)。 こっちはまあ、いざってとき用なんで、無難に Xfce とかでまとめたところ。 何も設定してないのにちゃんと音が鳴ってたな。 まあ、こっちのカーネルは 2.4 だけど。
そんな感じで Debian 分が他のマシンに移行されたので、今まで Debian が入ってた 5,000 円の省スペースデスクトップに、ようやく FreeBSD をインストールできた。 iMacG5 がメインマシンになって以来、VPC くらいでしか FreeBSD をいじってなかったから、久々の実機だ。 VPC の特性上、ファイルのハッシュ値をとる操作なんかが鬼のように遅いので(ディスクへの細かいアクセスに弱い)、ports で何かをインストールしたりとかってのが、はっきり言ってやる気を無くすレベルだったんで、ほとんどまともにいじってなかったのよね。 でも今度は実機だからさくさくさ。 まあ、モニタ事情が世知辛いんで、モニタレスな運用だけど。 あと当面は 6.0 のセキュリティブランチで行く予定。
『なんでも継続』でも説明されているとおり、『継続』というもの自体はどんな言語のどんな処理にも存在するわけだけど、call/cc の特異性というのは結局のところ、その継続の状態を任意の時点で切り取ることができるところにあるんだろう。
てなことを考えたときに、「ああ、Python の yield 文って(限定された用途の) call/cc じゃね?」と思ったのであった。 yield 文てのはジェネレータ関数を定義するときに使われるもので、ジェネレータ関数ってのはイテレータオブジェクトを自動作成して返す関数だ。
Python のコレクション的なオブジェクト(Ruby で言えば Enumerable を include してるオブジェクト)は iter() 関数を使うことでイテレータオブジェクトを取得できる。 イテレータオブジェクトは next() というメソッドを持っていて、呼ぶごとに次の値を取り出せるという寸法。 Ruby のイテレータよりは、Java の Iterator クラスに近い。 んで、for 文にオブジェクトを渡すと、自動的にイテレータオブジェクトを取得して、勝手に next() を使ってループを回してくれる仕組みになっている(Java も 1.5 になって、そういうようなことができるようになったんだっけ?)。
ジェネレータ関数というのは、このイテレータオブジェクトを直接(オブジェクトを介さずに)作ってしまう関数のことだ。 で、yield 文ってのはジェネレータ関数のためだけに存在していて、ジェネレータ関数は呼ばれるとその関数の中身をイテレータオブジェクトとして返すわけだけど、そのイテレータの next() 関数が呼ばれると、yield 文まで進んでその文が持つ値を next() の返り値として返す。 そして、次に next() が呼ばれるまでは前回 yield が処理された時点で止まっている形になる。 これって要するに関数の途中経過(継続)を保存していると言えるんじゃなかろうか。
実際の実装がどうなってるか知らないから単なる妄想だが、いずれ Python は yield を拡張してほんとに call/cc みたいなのを作るかもわからんね。
ちなみにジェネレータ関数が『ジェネレータ』であって『イテレータ』でないのは、必ずしも内部の実装が繰り返し(iteration)である必要がないからだと思われる。 ぶっちゃけこんなんでもジェネレータ関数としては合法。
>>> def gen(): ... yield(1) ... yield(2) ... yield(3) ... >>> for i in gen(): ... print i ... 1 2 3
継続について調べるまでは、たまに Ruby のメーリングリストとかで話題に上る callcc って何だよ?と思ってたわけだけど、これってまさしく call-with-current-continuation なわけね。 ただ、継続のありがたみがわかってない状態で、しかも callcc の話になると必ずと言っていいほど「遅い」「重い」って話になるから、あんまり深く追求しないでいたのである(例:Generator)。
んで、Scheme の継続に興味を持ったのは、少なくともこれについて「遅い」とか「重い」とか記述されてるのを見たことが無いから(実際がどうなのかは知らないけど)。 むしろ「継続を使いこなせねば Scheme 使いに非ず」みたいな雰囲気すらあるでしょ。あるよね?
ともあれ、Scheme における継続のありがたみについては、まだまだ勉強するつもりだけど、Ruby における継続についてはあんまり深く追求するつもりは無かったりするのであった。 いや、わりと嫌われ者っぽいし?(笑
ちょろちょろググってたら RHG の関連ページで継続ネタを見つけたから貼っとこう。 ああ、RHG の HTML 版も落としただけで結局読んでないなあ……
このページの前半で示されている継続の利用例は、まさしく Generator だなあと思った。 Ruby の Generator はこんな感じで作られてるのかね。
ちなみに Generator#yield ってメソッドは、昨日書いた Python の yield 文と同じ働きだね。 通常の yield とは似ても似つかない気がするが。 つーかぶっちゃけ Generator なんてクラスの存在を今まで知らなかったんだが(苦笑)、これっていつからあるんだろうか(いや『1.6.8から1.8.0への変更点(まとめ)』とかにも書いてないってことは昔からあるんだろうな)。
まあ、普通にイテレータを使ってる分には、あまり知る必要が無いものだったりするし(…するよね?)、知らなくてもあんまし困らないでしょ。 Python だって、2.4 からできたジェネレータ式とかが無かったら敢えて調べたりしなかったと思うし(そもそも Python はろくに使ってないけど)。
新しい言語に触ると、ついついオブジェクト指向システムを重点的に調べてしまうわしなのである。 逆に言うと、オブジェクト指向の機構が無い言語はイマイチそそられなかったりする。 だから SML とかツマンネ。 Haskell もクラスとかインスタンスとかって言葉は出てくるけど、ありゃなんか別のもんだし微妙。
んでまあ Gauche だけども、こっそり(?)全ての値はオブジェクトであったりするらしい。 で、オブジェクトシステムは CLOS の影響を受けたものだそうな。 クラスが保持するのは変数(スロットと呼ばれる)のみで、メソッドテーブルはグローバルにあって、メソッド呼び出し時の引数の型によって動的にディスパッチされる。
メソッドがクラスそのものには関連付けされてないのはおもしろい。 まあ、スロットに関数を突っ込んでやれば、クラスに関連付けするのも可能ではあるけど。
% cat class_test.scm
(define-class <hoge> ()
((print :init-value
(lambda () (print "hoge")))))
(define o (make <hoge>))
((ref o 'print))
% gosh class_test.scm
hoge
でもまあ無理してこんなことする意味はあんまし無いとは思う。 真っ当な使い方の基本的な例はこんなの。
% cat class_test2.scm
(define-class <hoge> ()
((v :init-value 10)))
(define-class <fuga> ()
((v :init-value 20)))
(define-class <foo> ()
((var :init-value "foo")))
(define-class <bar> ()
((var :init-value "bar")))
(define-method add (x y)
(+ (ref x 'v) (ref y 'v))) ;; line 11
(define-method add ((x <foo>) (y <bar>))
(string-append (ref x 'var) (ref y 'var)))
(define hoge (make <hoge>))
(define fuga (make <fuga>))
(define foo (make <foo>))
(define bar (make <bar>))
(define (print&eval e)
(display e) (display " => ")
(print (eval e (interaction-environment)))) ;; line 22
(print&eval '(add hoge fuga))
(print&eval '(add fuga hoge))
(print&eval '(add foo bar))
(print&eval '(add bar foo))
% gosh class_test2.scm
(add hoge fuga) => 30
(add fuga hoge) => 30
(add foo bar) => foobar
*** ERROR: object of class #<class <bar>> doesn't have such slot: v
Stack Trace:
_______________________________________
0 (ref x 'v)
At line 11 of "./class_test2.scm"
1 (eval e (interaction-environment))
At line 22 of "./class_test2.scm"
これ以上無く Gauche のオブジェクトシステムの特徴を端的に表しているコード……だと思う。たぶん。 あと、print&eval みたいな関数を作ってみると、S 式と eval のおもしろさが垣間見れるね。 Ruby の eval とはまたちょっと違ったおもしろさがある。 それはともかく、上記の例が示すところは要するに、
Gauche では全ての値はオブジェクトだから、こんないたずらもできる。
gosh> (define-method + ((x <integer>) (y <integer>)) (print x) (print y)) #<generic + (1)> gosh> (+ 1.0 2.0) 3.0 gosh> (+ 1 2) 1 2
こんなことするのは無茶だけど、次のようなのはそれなりに便利かもしれない。
gosh> (define-method + ((x <string>) (y <string>)) (string-append x y)) #<generic + (2)> gosh> (+ "hoge" "fuga") "hogefuga"
オブジェクト指向がどうのというよりも、動的型付けの柔軟性を生かしつつ引数の型を特定のものに限定した関数が書けるのはわりと便利かもなあと思った。
わしが関数オーバーロードを好かんのは、せっかくきっちり型付けされているものを適用範囲が広げる方向に進むからで、逆にこういう広い適用範囲を狭くする方向に働く使われ方は結構好みだな。
例えば OCaml で…
# let iter = List.iter (fun x -> print_endline x);; val iter : string list -> unit = <fun> # let _ = iter ["this"; "is"; "a"; "pen"];; this is a pen - : unit = ()
みたいなことがしたいときに…
gosh> (define iter (for-each (lambda (x) (print x))))
*** ERROR: wrong number of arguments for #<subr for-each> (required 2, got 1)
Stack Trace:
_______________________________________
0 (for-each (lambda (x) (print x)))
At line 1 of "(stdin)"
こんなんなって「ウガーッ!!」ってなったわけ。 なにそれテラナサケナス…とか思ったが、ちゃんと調べればあるじゃあないですか。
gosh> (define iter (pa$ for-each (lambda (x) (print x)))) iter gosh> (define lst '(this is a pen)) lst gosh> (iter lst) this is a pen #<undef>
うむうむ。 ちなみに for-each なら、
gosh> (define iter2 (for-each$ (lambda (x) (print x)))) iter2 gosh> (iter2 lst) this is a pen #<undef>
こうでも良いみたいね。 んで、なんだもうバッチリじゃん、と思ったら今度は eval とかでハマる。 引数の順序が逆だから pa$ が使えん...orz
…と思ったら、こんなマクロがあった。
gosh> (define eval-here (cut eval <> (interaction-environment))) eval-here gosh> (eval-here '(print "hoge")) hoge #<undef>
<> の部分を引数にしたラムダ式に変換されるらしい。 これは便利だ。
lisp 系言語のコード(S 式)を読み書きする際の注意点とかを、いろいろ眺めて回ったページの情報なんかを元にまとめてみる。 まず読む時。
式の最後に 5 個も 6 個も閉じカッコが付いてるとうんざりするんだけど、そんなもんは意識しちゃダメと。
(define (add&print x y)
(let ((sx (x->string x))
(sy (x->string y))
(result (+ x y))) ;;←こことか
(display (string-append sx "+" sy "="))
(print result))) ;;←こことか気にしちゃダメ!!
(add&print 2 3)
この例はわざと冗長に書いてみたんだが、これを OCaml で書くとだいたいこんな風になる。
let add_print x y = let sx = string_of_int x and sy = string_of_int y and result = x + y in print_string (sx ^ "+" ^ sy ^ "="); print_endline (string_of_int result) let _ = add_print 2 3
関数の引数を表す方法が、単純に空白区切りなので、カッコのことを除けばわりと似ているような気もするね。 そんなところで、次は書くときの気構え。
C とかその影響を受けてる言語に馴染みのある人は、一つの式はみんな関数適用だと思えば良いんじゃないかな。
printf("hoge");
が、lisp では
(printf "hoge")
こうなる。カッコの位置が違うだけで、数は変わらんでしょ。 変数の宣言も全部関数だと考える。
(define hoge "hoge")
は、
define(hoge, "hoge");
こんな感じのものだと思えば良い。
インデントは真っ当なエディタを使えば大抵 lisp 支援機能が付いてるはずなんで、それに任せてしまうのが良い。 変に自分で調節しようとか思うと面倒になるだけだし。 ちなみに vim だと :set lisp すれば lisp 支援機能が有効になる。 上記のコードも vim で書いたもの。
ついでに tips も書いとくと、vi コマンド =[action] でインデントの再調整ができる。 カーソル行だけを対象にするなら = = で、ファイル全体なら gg でファイル頭に移動して =G とか。 ヴィジュアルモードで選択して = でも可。 これらは lisp モードだけじゃなくて、通常のインデント支援でも使えるから憶えておくと便利。
最後の閉じカッコもエディタの支援で何も考えずに辻褄を合わせてやると良い。 vim の場合は :set showmatch すると閉じカッコを入力したときに対応する開きカッコに一瞬跳ぶようになるので、それを目安にして数を整える。
こんな感じでがんばっとるところ。 最終的にはどこぞの偉い人みたいに「カッコ?ああ、そんなものもあったっけね」とか言えるくらいに……は、ならなくても良いな、別に(苦笑
最近憶えたレコーディングの使い方をメモ。
同じ入力を、任意の場所で何度も繰り返さなきゃならないような時、今までは :map でいちいち定義してたんだけど、ちょっとしたことならこのレコーディングを使った方がラクチンだ。 そもそも map なんて滅多に使うことないから(いつも使うものなら一度定義して終わりだし)、定義の文法を思い出すだけでひと苦労だったりするし。
で、レコーディングってのは簡易的な map みたいなもんで、キーボード操作を記録していつでも再生できるようにするものだ。 詳細は :help recording すれば見れるけど、簡単に説明すると…
使い方は知らなくても、意図せずレコーディングモードに入っちゃってハマっちゃう人はいるような気がする。 つーかわしのことだが。:q と入力するつもりが手が滑って : を入れ損ね、さらに焦って適当なキーを押しちゃうとレコーディングモードに突入だ。 抜け方知らないとなかなか抜けられないんだよな。 まあ、最悪そのまま :q とかで終了しちゃえば良いんだけどさ(苦笑
『新規ウィンドウを開くリンクは次の場所に開く』の設定がとてもよろしい。 頼むから Safari も早いとここういう設定できるようにしてくれ。
つーか、外部リンクにはことごとく target="_blank" を指定してくれやがるどこぞのサイトとか、もう死んでくれって感じだよね。 ウィンドウ開くのウザいから中クリックで新タブに開くように気を付けてるんだけど、たまにうっかり普通にクリックしちゃって新規ウィンドウ開かれたときの血の昇りっぷりったら、もう……
ごほん、それはともかく。 iMacG5 に入れてる Firefox は bbs2chreader 専用だから、こいつが 1.5 対応された時点でさくっとアップデートした。 でも mozex を使う必要がある環境は、まだ上げれないなあ。 つーか、mozex はちゃんと対応されるんだろうか。 別に mozex じゃなくても良いから、とにかく外部エディタを使うための機能拡張が無いと困るよね、実際。 やっぱ w3m + vim が最強かぁ……
mozex のようにテキストフィールドで外部エディタを使うための機能拡張。 ……なんだけど、どうもうまく動かない。むう。
とりあえず Developer Comments に書いてあるように MacOSX で動かないのはまあ仕方ないんだが(そもそもエディタを起動できなかった)、FreeBSD に入れた方でもうまく行かないのが寂しい。 一応エディタは起動させられるんだけど、すでに書き込んであったテキストがエディタの方に渡されないし、エディタで書いたものもブラウザの方に渡されない。 これじゃ意味無し。
LANG を ja_JP.UTF-8 とかにしてみたけど、ダメ。 せっかく 1.5 でも動く mozex の代わりが見つかったと思ったのに……
あと念のため、Mac の方でも fink で Firefox 1.0.7 を入れて試してみようと思ったんだが、なぜか『Editus Externus 0.9.1 will only work with Firefox versions from 1.0+ to 1.6』とか言われてインストールを拒否される。 わけわかんねえ。
Windows でも試してみないといかんな。
(追記)::Windows の Firefox 1.5 だと、さくっとうまく動いた。 なんで FreeBSD だとうまくいかんのかなあ……
仕方ないので次善の策。 テキストフィールドのテキストをファイルに保存したり、ファイルから呼び出したりする機能拡張。 ファイルの文字コードを utf-8 にしてやり取りすれば、日本語も問題無く通る模様。 mozex に比べると、いちいち保存したり読み込んだりを自分でやらなきゃならないのがかったるい。 でもまあ、動かないよりはマシだしねえ。
これは一応 MacOSX 版でも動く。 けどテキストファイルの改行を Mac 形式(CR のみ)にしないとファイルの読み込みに失敗するみたい。
声優とかモー娘。とかなんでこんなに多いのかと(笑
それはともかく、変なのいくつか見つけたんで名前だけ晒しときまそ。 興味のある人は適当に検索して見に行ってくださいな。
あと Ruby on Rails のリングが二つあったね。 どうして被るかなあ。
ちなみにわしはどこにも所属してません。 何が楽しいのかわからないんで。
だんだんこの気持ち悪さが快感になってきて……ないない(笑
一つ目の例は、まあオーバーロードを解決するときの順序がきっちり決まっているんであれば、「そう言うもんか」で納得できそうではある。
二つ目は結構気持ち悪いけど、オーバーロードの解決よりも前にリファレンスが解決されてしまってる(?)ようなイメージで見れば、全部の呼び出しが bar(double) だってのも納得できるようなできないような。 リファレンスの特性上仕方ないという気もする。 つーかこの辺が個人的に「リファレンスキモイ」と思う所以であるような感じかも。
リファレンス使わないでポインタにすれば…
% cat pointer.cpp
#include <iostream>
using namespace std;
template< typename t > void bar( t );
template<> void bar( double ){ cout << "template<> void bar(double)" << endl; }
template<> void bar( double * ){ cout << "template<> void bar(double *)" << endl; }
template<> void bar( const double * ){ cout << "template<> void bar(const double *)" << endl; }
int main() {
double d=1.0;
double * r = &d;
const double * cr = &d;
bar( d );
bar( r );
bar( cr );
bar( (double *)&d );
bar( (const double *)&d );
return 0;
}
% g++ -Wall pointer.cpp % ./a.out template<> void bar(double) template<> void bar(double *) template<> void bar(const double *) template<> void bar(double *) template<> void bar(const double *)
何か、ほっとする(笑
この前「Epiphany で IM の切り替えができない」みたいなことを書いたが、Gnome を使ってるなら uim-applet-gnome を入れれば何とかなるのが判明した。
これを入れとけば、gtkim を使ってるアプリケーションに関しては全部ここで制御してくれるっぽい。 それ以外はどうせ uim-xim を使わなきゃいけないんだから、どっちみち泥臭くやるしかないんだろう。 つーことで、gtk2 だけで完結できれば、それなりに快適にすごせそうではある……かも知れない。
日本語フォントに変な隙間が空く現象はいつになったら直るのかと。 Mona フォント(どっかで見つけてきた TTF 版)とか IPA モナフォント(これもどっかで拾ってきた)とか使っても AA ずれるし最低。 ちなみにこれらを Safari で使えばちゃんと表示されるよ。
ほとんど 2ch 専用で使ってるのに、それは無いよなあ。 んで、昨日の Editus Externus 関係のごたごたで X 版の Firefox を入れたんで、試しに元祖モナフォントを突っ込んでみたらキレイに表示されるのな。 Carbon 版だけ低クオリティなのが確定した模様。 もう良いや、さよならだ。 わしは X 版を使うよ。 fink の Firefox も早く 1.5 になんないかな。
ちなみに、わしは祖父の遺言により(嘘)、X Window System を使う際はアンチエイリアスをオフにしておる。 つーかね、MacOSX で使うときは他のアプリと X アプリのレンダリングの性能が違いすぎてがっかりするのよね。 そこで眉に唾付けてる人、試しに東風フォントとかを MacOSX で使ってみなさいな。 ttf ファイル(kochi-gothic-subst.ttf とかってのね)を ~/Library/Fonts に突っ込めば使えるから。 東風フォントってこんなに綺麗だったのかってびっくりするよ。 まあ、それでもやっぱりヒラギノの方が綺麗だから、無理に使う必要は無いんだけど。
ところで X でアンチエイリアスをオフにする方法は、~/.Xresources 辺りに
Xft*antialias: False
って書いとく。 たまにアプリ独自でオンオフを制御してるものもあるけど(mlterm とか)、それはそれで適当に設定。
とりあえずデフォルトのテーマだと格好悪すぎるんで、適当に探す。 と言っても、fink でインストールするのが前提だから、使えるパッケージは gnome-themes-panther か gnome-themes-extras くらいしか無い(はず)。 少なくとも gnome-themes-panther はダサすぎるんでやめた方が良い。
んで、gnome-themes-extras の中では何が良いかと言うと、個人的には Industrial が真っ白くて(?) MacOSX にマッチしてる気がする。 gnome 本体無しでテーマだけ使いたい場合は、~/.gtkrc-2.0 ってファイルに
include "/sw/share/themes/Industrial/gtk-2.0/gtkrc" gtk-font-name = "Kochi Gothic 9"
とか書いとくと良い。 フォント名はおまけ。 ちなみにこのフォントサイズは DPI が 96 の場合のもので、DPI を設定してないときは 12 が同じサイズになると思った。 (DPI の設定とかは過去の日記参照)
via Matzにっき。
実はこの前の Editus Externus には困った制限があるのが判明したので、どうしようかと思ってたから非常に助かる。 制限ってのは『外部エディタ起動中はブラウザを操作できない』こと。 日記の更新とかだと、URI をペタペタ貼り付けたりってことをするから、この制限はうまくない。
そんなわけで、mozex が使えるなら使ったほうが良いじゃない?てな感じで、ありがたく使わせていただく。
ここ見て「へえ、Boost には lambda があるんだ……一体どうやってんだ?」と思って調べてみた。 Boost には元々ちょっと興味があったんで、良い機会だし。
boost::lambda (Let's boost より)
ひっくり返った。 何、この謎言語(笑
なんか Python の lambda 並に存在意義が微妙なものって気がするね。 ちなみに、Python の lambda は式を一つしか書けないんで、ろくな使い方ができないと思われる。 クロージャが欲しいなら、素直にネストした関数を作ってそれを使うのが Python 流(だと思う)。 C++ は関数のネストってできたっけ?(できたとして、それをクロージャ的に使えるかはまた別の問題かな)
Cygwin 上で自前で何かを make してやろうとするとたまにあるんだけど、configure では見つかって使うように設定されるくせに、なぜかリンクのときに見つけられずにエラーになるってパターン。 今回は libiconv と libgdbm が該当。 正直何が悪いのかわからん。 話題にならないってことは、たぶんわしの環境が腐ってるんだとは思うんだが……
んで、結局 configure のときに…
./configure --with-iconv=/usr --with-local=/usr
とかしてやるとうまく行ったりすんのね。アホみたいだ。 ともあれ、うまく行ったんだから善しとしとこう。
大パチンを当てて一気にかけよりザンギュラとザンギエラの二択を迫り
お腹痛すぎ。 元ネタを知らない人はガイドラインの 3-4 を見るべし。 メストネタの元はどこだか知らん。
Carbon な Firefox に見切りを付けて AA がずれなくなったから AA スレが楽しくて仕方がないぜ。 てことで、タンヤオのガイドラインとか見てしまうわし。
とりあえず 7 がわりとツボった。
VisualStudio とか Eclipse とかの IDE には大抵付いてる、関数やなんかを折り畳んで短く表示する機能。 まあ、そういうのほどキレイに使えるわけでもないけど、知っとくとそれなりに便利。 わしは .vimrc にこんな風に設定してる。
set foldmethod=indent set nofoldenable
foldmethod は折り畳みをする基準をどうするか。 nofoldenable は folding を OFF にする。 デフォルトは ON なんだけど、ファイルを開いた時畳まれた状態で始まるのが好きじゃないんで。 ON/OFF は vi コマンド『zi』でトグルできる。
あと、『zo/zO』で開く(それぞれ一段ずつと、ネストしたの全部)、『zc/zC』で畳む(一段、全段)、『zR』でファイル全体の畳み込みを開く、『zM』で畳めるところ全部畳む。 他にもごちゃごちゃあるけど、憶えきれないんでこれくらいで妥協してる。 くわしくは :help folding してちょうだい。
foldmethod はいくつかあるけど、とりあえず使う…って場合は多分 indent が一番妥当だと思う。 シンタックスルールが folding に対応してれば syntax の方がキレイに畳めるかも知れないが、わしが OCaml のルールが対応してない時点で捨ててるね。 indent と syntax は自動的に折り畳めるポイントが決まる。 diff もそうみたいだけど、これは vim が diff モードで動いてるときじゃないと使えないっぽい。 これらの自動ルールは、簡単だけどその分あんまり頭が良くないのがたまにきず。
manual は自分でちまちまマーカーを設定する方法。 マーカーはメタデータとしてテキストとは別に保存しないと消える。 すごく微妙。 これ使うくらいなら marker を使った方が良い。
marker はテキストでマーカーを書く方法。 詳細は :help fold-marker を。 でもいちいちコメントにこんな変な記号書いてくのも、ちょっと微妙。
凝ったことしたいなら、多分 expr が一番。 ただ、個人的にはヘルプ(:help fold-expr)を見た時点であまりにめんどくさそうだったから試してもいない(苦笑
まあ、とりあえずは foldmethod=indent で十分だと思う。
OCaml のせいでパターンマッチが無いと寂しくて仕方ない身体になってしまったわし。 たしか Scheme ではパターンマッチを実現するマクロがあるって話だったよな…と思って探す。 ……判明。
普通に使えるっぽい。 つーか型に縛られない分、OCaml のものより柔軟性は高いかも。 やっぱ Ruby にもこういうの欲しいなあ。
昨日の疑問。 ローカルクラスを使えば関数内関数は一応作れるみたいだね。
#include <iostream>
using namespace std;
typedef int (*fp)(int);
fp hoge() {
struct Local {
static int nested_func(int y) { return 10 + y; }
};
return Local::nested_func;
}
int main() {
fp f = hoge();
cout << f(20) << endl;
return 0;
}
ただ、スコープ内のローカル変数を参照できないから、あんまり意味無い気もする。 まあ、ローカル変数をローカルクラス内に突っ込んでしまえば良いかもしれないが、それはそれでぐだぐだだし。
ちなみに D にはクロージャ(関数リテラル、ネストした関数)があるようだ。
ところで上記のコードで hoge() が返すポインタは有効なんだろうか。 とりあえずこの例では動くけども……
Mac で X Window 版 Firefox にうっかり GoogleToolbar をインストールしてしまうと起動できなくなるぞ。 つーか、ツールバーごときにネイティブなバイナリ使うなよな。 結局どう直したら良いかわからんから、新しくプロファイルを作り直すはめになったじゃないか。
そんなわけで、最初っからそうすべきだったんだろうけど Googlebar を入れて終了。
Ruby の case..when で正規表現を使うような使い方をしたい場合、
(define (f x)
(cond
((#/hoge/ x) (print "hoge"))
((#/fuga/ x) (print "fuga"))
(else (print "no matched"))))
みたいな書き方を想定してたんだけど、util.match を使えば
(use util.match)
(define (f x)
(match x
((? #/hoge/) (print "hoge"))
((? #/fuga/) (print "fuga"))
(_ (print "no matched"))))
みたいに書けるね。あるいは、
(define f
(match-lambda
((? #/hoge/) (print "hoge"))
((? #/fuga/) (print "fuga"))
(_ (print "no matched"))))
とか。 条件式に変数名を書かなくていいってのは、地味だけどありがたい(だからこそ case..when が好きなんだけど)。 修正もしやすいし。
shiro さんからツッコミを受けて、ちょっとドキドキしてしまったミーハーなわしである。
それはともあれ使ってみた。
gosh>
(define (f x)
(rxmatch-case x
(#/(hoge|fuga)/ (m) (print m))
(else (print "no matched"))))
f
gosh> (f "hogehoge")
hoge
#<undef>
gosh> (f "fugafuga")
fuga
#<undef>
gosh> (f "foobar")
no matched
#<undef>
util.match に比べて、正規表現にマッチした結果を変数に束縛してくれるのが激しく便利(上の例では m というやつ)。 Gauche のわしに対する好感度がさらにアップした模様。
これ(2ch)を見て、どっかで見たことあるネタだなあ…と思ったんだけど、どこで見たんだったか思い出せなくて、仕方ないから実例になるような短いコードでも書いてみようと思ったわけ。 でも、ちょろっと貼付けられるような短いコードで、かつ、あまりわざとらしくならない例を作ろうと思うとこれがなかなか難しい。
10 分くらい試行錯誤して結局めんどくさくなって、頭に来て書いたのがこれ。
main(){int*p=main;*p=0;main();}
元ネタとは全然関係無い自殺コード。 世界一非生産的。 コンパイル時の警告を 0 にしようと思うともう少し長くなるが。
これより短い自殺法はあるかなあ……
一年前のネタにツッコミが付いてびっくり。 長年日記の効果かしら?
ともあれ、
extlibのは末尾再帰になってるそうです。
に、「へぇー」と思ってさっそくソースを見てみた。
let fold_right_max = 1000
let fold_right f l init =
let rec tail_loop acc = function
| [] -> acc
| h :: t -> tail_loop (f h acc) t
in
let rec loop n = function
| [] -> init
| h :: t ->
if n < fold_right_max then
f h (loop (n+1) t)
else
f h (tail_loop init (rev t))
in
loop 0 l
えーと、ライセンスは LGPL だからコピペしても問題無いよね。 どうやら、ループが 1000 回になるまでは普通にやって、それを超えたらリストを逆向きにして fold_left 相当のことをやってるみたいね。 最初っから List.rev しちゃわないのはメモリ効率とかの問題かねえ。
鍋谷さんが自殺ネタに乗ってくれたようなんで見てみた。
main=0;
うはっ、こんなのまったく思いつかなかった。 でもよく考えてみれば、これって実際起こってるのはわしが書いたコードと同じことだね(ただしこちらは一回目の main 呼び出しで死んでいる)。 納得。
main(){main();}
わしの環境(MacOSX10.4.3/gcc4)では SEGV で死んだ。 即死しなくても、ずっと置いとけばいつかはスタック溢れると思うけど(いまどきのマシンじゃ相当時間かかるかな)。
main(){*(int*)0=0;}
main(){++0[(int*)0];}
ゼロ番地への書き込みで即死するなんて知らなかった。 もしかして規格で書き込み不可って決まってるんだっけか? ともあれ修行が足りませんなあ。
main(){(main-999)();}
main 関数のアドレスをさかのぼって…ってのはわしも考えたけど、こんな書き方できるとは(苦笑)。 どの辺までさかのぼれば死ぬかは、環境依存でしょうな。
main(){++*((int*)main);}
えーと、main 関数の実体があるのが書き込み不可領域だってことかなあ。 なんとなく処理系依存くさい。
main(){memset(0,0,-1);}
ゼロ番地への書き込みが即死だと認識してしまえば、たしかにこれは「死にます」っていう意思がはっきり見える力強さ満点な方法ですね(笑
main(){((int(*)())0)();}
アドレスが 0 な関数を呼ぶ方法。こんな書き方もできたのか。
main(){main(*(int*)main=0);}
これも main が書き込み不可領域にある関係?ちょっとピンと来ない。
ああ楽しかった。 普段、当然のように『やらない』ことを敢えてやってみるのも結構楽しいもんですなあ。
inside out での話。 Rosetta って SSE3 が無いと動かないのか。 とすれば、SSE3 が搭載されていない PenM では新しい Mac は出せないだろうなあ。 何たって Rosetta は for Intel のウリの一つだしねえ。
ところで『Thinkpad T42p にMac OS X for Intel を入れて使っている。』みたいな話は、公然と語って良い類のものなんだっけ?
つらかった……いろんな意味で。 とりあえず、エンディングは4つあるうちの一番悪いのらしい。 見るからにバッドエンドくさかったもんな。
攻略サイトを見ると、もっと良いエンディングを見るためにはかなりがんばらないといけないっぽいのがちょっとなあ。 イマイチ何度もやる気にならんが…… もう少し使いやすい武器があれば良いんだけど。
上級編をやり始めてからはずっとベイダー一本に絞って使ってたんだが(上級は距離感がずれるとつらい)、そろそろ飽きてきたんでニーナ姉さんに変更してみたり。 それでもやっぱりマンネリ感が漂う今日この頃なんで、こんな日のために頑なに守り通してきたミラーモードの封印を解くことにした。
総試合数 300 を数えるまでやり込んでからのミラーモードは、すげぇ新鮮だ(笑
まるで別のコースをやってるみたいで、またもや熱が戻りつつあるぞ。 ストレートボールのキャラを使ってると、ミラーでも大して変わらないんだけど、クセ球のキャラを使ってると左右逆になるだけで攻め方まで変えないといけないんだよね。
自殺ネタの解説。ためになる。
それにしても、わしちょっと勘違いしてたな。
main(){int*p=main;*p=0;main();}
これ実は *p=0; の時点で死んでる模様。 最後に main を呼んだ時点で死ぬつもりだったんだけど、main の実体がある場所が書き込み不可だってことのようだ。 つーか、少なくともうちの環境では、main に限らず関数の実体に書き込むのは全部アウトらしい。
上記のコードが意図してるように『中身が変な関数を呼んで殺す(狂わす)』には、関数のポインタ値をいじって呼び出してやるのが良いみたい。 いや、そもそも良くないことしてるんだけど。
ともあれ、こういう変なことをしたときにキレイに死んでくれるのが良い OS なわけだよね。 変なことしても死なないのが一番怖い。 OS が無い環境のコードとか書くときは、ちょっとしたミスで暴走させるのなんて簡単だから。
なんか、いつぞやのわしと同じ疑問を抱いてる人がいるな→『バカが征く』。
結局これって、変数の宣言/定義以外のときの添字演算子はポインタ演算に読み替えられちゃうという話の延長線だと思うんだけど、
hoge[2] → *(hoge + 2) fuga[-1] → *(fuga - 1)
規格書には、この読み替えのことは書いてあるけど(あるはずだ)、その際に添字が負の値だったらどうするかは書いてない(はずだ)。 んで、宣言時の添字の範囲は 0 より大きくなければいけないということも書いてある(はずだ……はずばっかり)。
だから、添字の範囲が負になることはありえない…という意味で、fuga[-1] みたいなコードをエラーにするコンパイラがあってもおかしくない……のではないかと思う(自信無し)。 あるいは fuga[-1] を fuga[(unsigned)-1] みたいに読み替えるコンパイラとか(これは怖いな)。
まあ、現実にはそんなことするコンパイラは無いとは思うけど。 結局、個人的には気持ち悪いけど、規格的には間違ってるとも言えないんで「まあそんなもんか」と思って読むしかないかなと。 自分では書かないと思うけどね。
鍋谷さんとこのためになるシリーズ(また勝手に命名)。
配列の話と関数の話は知ってたが(厳密に言うと、これを見て「ああ、どっかで読んだな」と思い出した)、typedef の話は全然知らなかった。 いろいろ変なことがあるもんだねえ。
なんだよう、そんなこと言われたらへこむよ。 つーか自分ちのチラシの裏に何書いたって良いだろ〜。 lint の存在は知らなかったわけじゃないけど、たしかに全然使ったこと無かったよ。 わかったよ、今度から使うよ。ゴミみたいな雑談レベルのコードにもちゃんと使うよ。 てか、そんなコードしか書く機会無いんだよ、ぶっちゃけ。
あとね、偉そうに語ってるように見えるのは仕様なの。 そういうキャラ作りなの。 元々はアホなことを妙に偉そうに語るのが味のキャラだったの。 最近アホじゃないネタも混ざるようになっちゃったから、そこら辺が薄まってるだけなの。 中身は、いつ手斧が飛んでくるかと思ってビクビクしてる小心者の村人なの。 ね、そこら辺わかって?
変なこと言ってんなーと思ったら、
くらいにしといてちょうだい。 見かけによらず打たれ弱いから、なんか痛いのとか飛んできたらショック死しちゃうかも知れないからね。いや、マジで。
iPod nano を買ってすぐの頃、わしの車のヘボいステレオが壊れた。 厳密に言うと、どっか配線の接触が悪いだけだとは思うんだが、手の届く範囲でいじってみても直らないんで、放置して iPod で生活してきたのである。
ほんで、先月車検のときについでに見てもらったら、案の定すぐに直ったようでやれやれと思っておったんだが、昨日「今日あたり iPod 用の FM トランスミッタでも買いに行くかな」とか思ってたら……また壊れた。 お前はわしが iPod 使うのがそんなにイヤなのかと問いたい。問い詰め(略
さて、もうこいつはあてにならないので、カーステレオの力を借りずに車内で iPod をヘッドホン無しで使う方法を考えよう。 いや、一人で乗ってるときはヘッドホンでも良いんだけど、他の人を乗せるときはやっぱねえ。
2ch の Safari スレで見かけて『_blankリンクをタブで開く』って機能目当てで入れてみた。 便利だ。
この機能だけで十分お腹いっぱいだけど、他にもいろいろ機能があるんでちまちま試してみよう。
何だかんだ言いつつ、Inamode6 の初期の頃から住人だったりするわし。 まあ、当り障りの無いことしか書き込んだこと無いけど。
つーか、悪口言われて凹むのは確かだが、普段『人の悪口をよく言ってる』と言われるのは心外だぞ、1955 よ。 どっかの辛口トークがウリの人と一緒にしないでくれ。 たまにしか言ってないし、言うにしてもこっそり言ってるじゃんか。
いや、本筋と雑談を一緒くたに書いちゃうのはわしの悪い癖だよね。 バカ征くに対する話はそこで終わってて、残りは単なる雑談なんだ実際のところ。 つまりどうでもいい話。
そうか、読点じゃなく句点にしときゃも少しマシだったかな。
住人である事をカミングアウトしたことからわかるかも知れないが、昨日の胃が痛い云々はネタだから。 いや、概ね言ってる事は嘘じゃないんだけど、言うほどへこんでもいないし嫌がってもいないってことね。 本気で嫌だったら、そもそもあんなこと書かないでシカトするし(笑
でも、だからってノーダメージでもないから、むやみに貼らないでくれると嬉しいなとは思うですよ。 これはホント。
今日は路面状況が良かったんで、快適にセガラリー気分が味わえてご機嫌だよ。 やっぱ北海道の冬の醍醐味は、ファミリーカーでもスポーツカー気分が味わえることだよね(偏見があります)。
今日みたいに適度に滑る状態だと、アンダーステアを押さえ込みながらぐいぐい曲がっていくのが楽しい(わしの車は FF)。 でもスピードは最高でも 60km/h とか(笑
雪が降らないとこに住んでると、普通の人は『FR 車でアンダーステア』とか『FF 車でテールスライド』とか経験することないでしょ。 北海道なら大丈夫。誰でも経験できます。
ちなみに国産唯一の RR 車であるサンバーだと、テールスライドしたときに後輪が前輪を追い抜こうとする感じをばっちり体験できますよ。
まあ、路面が悪いときはそれはもう地獄なんだけども……
裏方面の某ゲームのエンディング曲の最後の部分の、のが多すぎるのは置いといて、その最後の部分を聴いて猛烈にグランディア2のエンディング曲『Cancao do povo』を思い出してしまって、聴きたくてしょうがなくなったからサントラを聴いたのである。
そしたら猛烈に泣けてきて、これはサントラだけじゃ物足りねえぜという気分になってしまったので、思わず買った PS2 版。 素直に DC でやっときゃ良いのに、なぜ買う。
3の新品が 2,980 円とかで売ってる御時世に、2の中古を 3,980 円で買うわし。 つーか店によっては 5,980 円とか付いててビビるよ。 プレミア付きに近いな。 まあ、それくらいの差はあるよなーとは思いつつも、やっぱりなんか納得いかない気もしなくもないのであった。 廉価版出してくれよ。 ……いや、もう買っちゃったから今さらなんだが。
マジか!!と思ってやってみたら本当だった。へぇ〜ボタン、へぇ〜ボタン。
でも、vi/vim で行指向の編集に慣れきっちゃってると、矩形編集なんてあんまりしないよなあ。 つーか、そもそも矩形編集が便利なシチュエーションってどんなときなんだろ。
eval のありがたみって思わずインタプリタを作りたくなっちゃうような類いのものだと思うんだけど、ほんとにインタプリタを作り始めちゃうとかったるいんで、とりあえず気分だけでもと思って逆ポーランド記法電卓とか作ってみた。
逆ポーランド記法ってスタックの例題なのが相場な気がするけど、適当にリストを切り貼りして eval してわーいみたいな感じを出したかったんで、あえてスタックとか木構造とか使わずに泥臭く書いてみたら、えらくぐだぐだになってしまった。
でもまあ、せっかく書いたから記念に貼っとこ。 エラー処理とか全然してないし、テストもろくにしてないから想定どおり動いてるのかわからんし、数値以外は単純にシンボルに変換して実行してるから何でもできてしまう変な物体だけど、eval のありがたみは感じられたような気がする。
(use util.match)
(define (make-expr buf orig ret)
(match orig
(() ret)
((x . xs)
(match (string->number x)
(#f
(cond
((null? buf)
(make-expr () xs
(cons (string->symbol x) ret)))
((eq? (length buf) 1)
(make-expr () xs
(list (string->symbol x) ret (car buf))))
(else
(make-expr
() xs
(let ((l (cons (string->symbol x) (reverse buf))))
(cond
((null? ret) l)
(else
(list ret l))))))))
(num
(make-expr (cons num buf) xs ret))))))
(define (main-loop)
(let ((str (read-line (standard-input-port))))
(if (eof-object? str) (exit 0))
(let ((result (make-expr () (string-split str #/\s/) ())))
(print (eval result (interaction-environment))))
(main-loop)))
(main-loop)
『慣れ』という要素はこの際無視して、理想論で書いてみる。
わしが思うにユーザインターフェイス(特にグラフィカルなもの)をデザインするにあたって一番大事なのは、視線の遷移を意識することである。 ある位置から自然な形で視線が誘導されていって、最後にちょうど最終的に押すべきボタンがあるというのが理想じゃないかと。 だから『左上から右下』に向かって読まれる文章が表示されているダイアログであれば、最後に押すべき確認ボタンは一番右下にあるべきだ。 逆に『右上から左下』に流れる文章なのであれば、一番左下にあるべきとなる。
ちなみに最近はそうでもなくなっててちょっとさみしいんだが、元々の MacOS では左上から右下へ視点が流れるようにデザインされているものなんである。 何事も左上から始まって右下で終わるのだ。 だからごみ箱も右下にあるのよ。
そういう意味で言うと Windows のダイアログなんかのボタン配置は、GUI のものではない。 あれは CUI 的な観点のものだ。 確認メッセージが出て『終了しますか?(Yes/No)』みたいな感じ。
それから何度か書いたことがあるけど、クリティカルな操作(ここでは簡単に取り消しできないような操作くらいの意味で)とそれ以外の操作のボタンを並べてはいけない。 だから個人的には『OK』と『cancel』が並んでるなんてもってのほかだと思ってる。 ちなみに BTRON だと決定ボタンは右下端、キャンセルボタンは左下端に配置されている。 たぶんこれが理想的。
別にわしは TRON 信者ではないけど、BTRON の UI 仕様には参考にすべき点がたくさんあると思う。 あれってわりと工業製品的な視点で決められてて、ヒューマンエラーを減らすように考えられてるから。
なんか相変わらずまとまりがない文章になったが、とりあえずこの辺で終わり。
BTRON3 仕様書とか見てみたけど、ボタン配置とかについては書いてないっぽいな。 HMI 仕様書(WEB では見つからないんでリンクはハンドブックのもの)に書いてるんだったかね。
一時期 TRON 関係の本を立ち読みしまくったことがあるんで(買えよ)、そのときに読んだのかも知れんな。 思い切って買っちゃっても良いんだけど、他にも欲しくて我慢してる本とかあるしやめとこ。 貧乏だから。
ヘッダ嫁。
具体的には stdlib.h ……じゃなくて、こいつが include してる何かだったと思うが。 sys/_types.h だったかな。家に帰らないとわからん。 たしか int32 だったような記憶がある。 まあ、それはどうでも良い。(以下本題)
そんで、他にググりようが無かったのかと適当に試してみたら、何か楽しげなのが見つかったんで保護。 →『神聖モテモテUNIX』(2ch)
stdlib.h -> _types.h -> sys/_types.h -> machine/_types.h -> ppc/_types.h (or i386/_types.h) という流れだった。 なんか i386 が入ったせいか、妙に複雑になってるな。 で、結局最終的にはこう(ppc も i386 も同じ)。
typedef int __darwin_ct_rune_t; /* ct_rune_t */
ppc64 でも int は 32bit なので、Mac OS X における wchar_t の大きさは 32bit(signed) ってことで終了。
あちらこちらの ML ユーザから orz の声が上がっている arton さんの記事。 他の言語を見る限り日本限定の話みたいだから、そう言う意味ではまったくその通りという感じではある。
OCaml.JP とか Wiki.OCaml.JP とか最近ほとんど更新されてないしねえ。 OCaml はそれでもマシな方で、SML なんかはこの手のものって見た事無い。 あとコミュニティってほどのもんではないけど、一応 2ch の ML スレはそれなりに活発じゃないかなあ。 はてなリングにこっそり『OCaml / F#』なんてのがあったりもする。
『SML』でググるとエロゲ会社が一番にヒットするって話があったっけ(苦笑
オブジェクト指向が導入された COBOL って普通にあるよね? なんだっけ、COBOL 2000 だったかなんだったか。 詳しく調べた事無いから、どんな感じなのかは知らないけど。
95 の
ネタキャラ以外なにができるって言うんだ
に対して、97 の
磁力でハニワを引き寄せられるんだぞ
が妙にツボに来た。 たしかにジーグブリーカーは磁力で引き寄せてる設定だった気がするが、よくよく考えたら磁力でハニワが引き寄せられるのはおかしいよな。 どんなハニワなんだ(笑
終わった。 やっぱマレッグの最期から続く怒濤の展開は神懸かり的だなあ。
リュード復活のところとか、格好良すぎて倒れそうになる。
あと最期の『一年後』演出も良いね。 特にラストの歌への繋ぎなんて、これだけでご飯三杯いけるよ。 つーか、これの印象強すぎて、3の最期がアホみたいにあっさりすぎたのに憤りを隠せなかったんだよな。 結婚して子供ができました…とかはどうでも良いんだよと。 自分たちが守った世界がどうなったかを見せろと。
ともあれ、良くも悪くもそのまんまな移植であった。 細かいグレードダウン(処理落ちとか)はあるけど、この際不問としよう。 DC がもし壊れてしまっても、この名作をプレイできるという事実には意味がある。
いや、『謎の』とか大仰に言うほどのもんじゃないだけど……
Hashtbl モジュールを使う時に、Hashtbl.create 0 で作る場合と、あらかじめ適当な大きさで作っておく場合でどれくらいパフォーマンスに差があるか調べてみたくて、こんなコードを書いたのね。
let _ =
let h = Hashtbl.create 0 in
for i = 1 to 1000000 do
Hashtbl.add h `hoge i
done
そしたらこれがスタックオーバフローになるわけ。 大量にハテナマークを浮かべながら、じゃあこうするとどうなの?と、やってみる。
let _ =
let num = 1000000 in
let ht = Hashtbl.create 0 in
let rec add h i =
match i with
| 0 -> ()
| n -> Hashtbl.add h `hoge i; add h (i - 1)
in
add ht num
明らかに末尾再帰だと思うんだけど、やっぱりオーバフロー。 例外が絡むと末尾再帰の最適化ができない場合があるみたいだけど、Hashtbl.add で例外が起こるって話は聞いた事無い。 結局ソース読むしか無いのか……
ってことで stdlib/hashtbl.ml を読む。 add の中には怪しい箇所は無し。 どうやら add から呼んでる resize が怪しい。 と言うか、それくらいしか怪しいのが無い。
で見てみたら、この resize の中で使われてる insert_bucket っていう再帰関数が末尾再帰になっていない模様。 んで、これがざっと見た感じ、現在の要素数分だけ再帰するように見える。 ああ、それはツライ。
そんなわけで、自動でサイズ変更してくれるから良いや…みたいなノリで安易に create のときに小さめの値を指定してると、場合によっては痛い目見るかもわからんよという話のようで。 ちなみに上のコードは、create に 0 じゃなく num を与えてやれば、問題無く動く。
まあ、そんなでかいハッシュテーブルが必要になることって稀なことかもしれないけど。
違うなあ、違うよ。 よくよく見たら、再帰が深くなるのは『同じキーの値がたくさんあるとき』だけだ。 そりゃ、一つのキーに何千個何万個の値を登録するなんて想定しないよなあ。 わしのテストの仕方がダメなだけじゃん...orz
let _ =
let num = 1000000 in
let ht = Hashtbl.create 0 in
let rec add h i =
match i with
| 0 -> ()
| n -> Hashtbl.add h i i; add h (i - 1)
in
add ht num
とでもしておくと平気ですた。
密かにスゴイと評判の日記を、わしもこっそりチェックしております。 めずらしく、わしでも付いてけそうなネタだったんで言及してみたり。
これって多分、動的ディスパッチの恩恵でしょうな。 Fib#fib の中で呼ばれてる fib は、FastFib#fib だという話だと思われ。 おもしろくもあり、気持ち悪くもあり、ってところ?
ちゃんと理解して使いこなせば、いろいろおもしろいことができそうだけど、よくわかんないままやるとまさにスパゲッティになりそうな予感。
こんな感じ?
% cat test.rb
class Parent
def hoge
fuga()
end
end
class Child < Parent
def hoge
super()
end
def fuga
p "fuga"
end
end
o = Child.new
o.hoge()
% ruby test.rb "fuga"
良かった。間違ってないよね、よね?
こうした方が良いかな。
class Parent
def hoge
fuga()
end
def fuga
p "Parent"
end
end
class Child < Parent
def hoge
super()
end
def fuga
p "Child"
end
end
o = Child.new
o.hoge()
% ruby test.rb "Child"
これなら Parent#hoge で呼んでる fuga が Child#fuga なのがはっきりする。
…ってとき困るよなあ、上記のような場合。 継承先でどんなメソッドを定義しても影響されないように、自分のクラスのメソッドを呼ぶ綺麗な方法って無いよね、たしか。 クラスメソッドにしてしまう手はあるけど、美しいとは言えない。 なんかこの辺の問題って一時 ruby-list 辺りで話題になってた気がするけど、結局どうなったんだっけか。
そう言えば Ruby の話じゃないけど、どっかで「無名関数内で自分自身を指すキーワードが欲しい」って言ってる人がいたなあ。 そうすればいちいち名前付けなくても無名関数のまま再帰できるからとか。 わしも、あればそれなりに嬉しいかもなあと思った。 Y コンビネータとかよくわからんし。
Ruby の場合は、メソッド検索を自分自身から始めるような仕組みがあれば良いんだろうなあ。 キーワードを追加しないでなんとかする方法は、ちょっと考えただけじゃ思いつかないけど。
mmatsuoka さんとこに何やらおもしろげなものが。 って言うかその前に、わしの自意識過剰でなければ…
2005年11月に Obj.magic を解析・解説して下さった方に感謝いたします。
これってわしのことでせうか?
……どうもわしのことっぽい。 めちゃ照れる。 つーか、別にわしが書かなくたって知ってる人は知ってるんだろうけど、とりあえず書いてみればどっかで誰かの役に立つこともあるんだなあ…などと感慨しきり。 たしかに日本語で Obj モジュールの使い方を書いてるのって、今のところわしくらいなもんかも知れないし。(Obj なんて酔狂な人が使うものという認識があるような気もするけど)
それにしても、なんかキャラがかぶるなあとは思ってたんだけど、もしかして mmatsuoka さんて _ さんと同一人物なのかな。
ともあれ試す。 コピペして〜
% ocamlc -c polyprint.mli polyprint.ml
% ocaml polyprint.cmo
Objective Caml version 3.08.4
# open Polyprint;;
# p [1;2;3];;
[1; 2; 3]
- : unit = ()
# ?= [1;2;3];;
[1; 2; 3]
- : int list = [1; 2; 3]
# p `Hoge;;
803991813
- : unit = ()
わーい。 variant なんかがうまく表示できないのは仕様のようなんで。 つーかこいつらは多分、コンパイル時にテーブルかなんか作っちゃわないと無理なんじゃないかなあ。 変数名なんかもそうだけど、コンパイルした時点で単なる内部用の ID かなんかに変換されちゃってて、元々の名前とかはバイナリ(もしくはバイトコード)に残ってないっぽいんだよね。 少なくとも、バイトコードとかに strings かけてもタグ名とかは出てこない。
ともあれ、これはこれで楽しいので、活用させていただきます。
Matzにっきを読んで、「Haskell の undefined みたいなもの?」とか思ったんだけど、そういう話じゃないですか、そうですか。
ちなみにわしは OCaml で何か書くときに、
exception NotImplemented let dummy x = raise NotImplemented
みたいのを定義しておいて、undefined みたいに『とりあえず置いておく』ようにしてますね。 とりあえずで良いからコンパイルが通るようにして、型付けが想定どおり行ってるか確かめたりするのに使ってますわい。
熱とか鼻とかは大した事ないんだけど、喉が痛いのと、あと腹にきてるのがツラい。 朝っぱらからギリギリでコンビニに駆け込んでトイレ借りるとか、マジ勘弁して欲しい(苦笑
その際、「いやあ、危うく社会的に死亡するところでしたよ、ハッハッハ」とか店員さんに言うのがデフォ(大嘘
いやあ、こりゃどうも。はげみになります。
ちなみに、外部からの TrackBack は今回が初めて…のはず。 文字化けとかしてなくて良かった。
% TrackBack [http://jijixi.azito.com/cgi-bin/diary/index.rb?date=200512..]