K.Sasada's Home Page

Diary - 2003 September

研究日記

長月

_30(Tue)

つくづく自分が素人であることを思い知らされる。うーん。


学校着。ローラースケートかスケボーか知らないけど、それに乗っている自分を犬に引かせている人を見かける。いいなぁ、あれ。


すかたん(Tue Sep 30 00:40:54 JST 2003)

ほとんど身内向けのアンケートでねぇか。大体、パンピーがHaskell使うわきゃねーし。

身内向けのアンケートという点、まったくそのとおりで。もしかして、注意書きが必要でしたか?


あくせく働くのではなく賢く働こう: Kent Beck氏へのインタビュー(dpml)。最後の、

Beck:Javaは非常に悲観的だと思います。Javaのコンパイラに「このプログラムは実行できるか分かりません。だから実行しません」と言われたことがあるでしょう。私は、悲観的な言語の安全性とは幻想である、ということに気づいています。

は、どういう意味なんだろう? コンパイラを満足させれば、それで大丈夫だ、というのは幻想、という意味? 彼の著作物を読んだことがないのだけれど、ちゃんと読まないとなぁ。


よし、動いた。

これって、ホントに日記じゃなくてメモだな...。

そういえば、先週の秋葉原での散在散財とか、今週の温泉とかの散在散財のために、銀行行かなければ...。


うわ、ほんとに月姫アニメ化するんですね。うわー・・・。


外は明るくなってきたが、バグは取れない。

yacc の使い方がわかんない。うーーー・・・。


10月のPTT。インタプリタ生成系 Virtual Machine Builder の紹介ということで、もちろん行きます。

とても楽しみな反面、私が出来ることがどんどん少なくなっていくなぁという危機感が。


やっと騙し騙しコンパイラが通ったー。騙し騙しじゃダメなんだけど・・・。


というわけで、諸々の理由により cygwin のアップデート。


あまり騙さなくても良くなってきた。


cygwin 入れ替えたら cat が使えなくなってた。何故?

うーん、現状の奴と、バージョンをぐちゃぐちゃにしたからなようで。ヤレヤレ。


Debugging with GDB

何度目かの挑戦。


なんか今日はずっとデバッグやってた気がする。そして明日もこんな日な予感。うわーん。

_すかたん(Tue Sep 30 01:44:07 JST 2003)

 はいはい、ぜひ、アンケートのツボなんかも一緒に書いてあるとうれしいね。

_ささだ(Tue Sep 30 02:14:08 JST 2003)

 アンケートのツボってどんなのでしょ。

_匿名希望(Tue Sep 30 10:13:07 JST 2003)

散在というのは、わざとなのか、誤記なのか、どっちでしょう? :)

_ささだ(Tue Sep 30 10:45:55 JST 2003)

 素で気づきませんでした・・・>散在

_maeda(Tue Sep 30 11:45:52 JST 2003)

悲観的な言語の安全性

たとえば,↓をコンパイルエラーを出ないように変えたとしても,何も安全に なるわけではないということでは?

class Pessimism {
    public static void main(String[] args) throws ClassNotFoundException {
        int foo;
        if (args.length != 1) {
            System.exit(1);
        }
        if (Class.forName(args[0]) instanceof Class) {
            foo = 1;
        }
        System.out.println(foo);
    }
}

ところでこの記事の日本語訳,原文の最後の節が1つ欠けてるね. Working smarter, not harder: An interview with Kent Beck

_ささだ(Tue Sep 30 17:00:27 JST 2003)

 すみません、どの辺が危険なのかわかりません・・・。

_shudo(Tue Sep 30 20:01:52 JST 2003)

 コンパイラがプログラマに対していろいろ警告してあげても、その警告は結局のところ、プログラマに対して catch (Exception e) {/* 空 */} というような危険なコードを書くような圧力をかけてしまうだけのことで、よい導き方ではない。 ということ???>悲観的な言語の安全性は幻想でしかない

_maeda(Tue Sep 30 22:05:22 JST 2003)

上のコード例は「fooが未代入で使われることはないのに,コンパイラにはそ れが分からなくてエラーになる」例のつもりです.

Javaのスタンスは,

安全であることを『コンパイラが証明できなければ』エラー

というものですよね.私自身は別にそう悪くないと思ってます(せっかく型付 きの言語ならそこまでやって欲しい).

Beck氏の意見を想像するに,以下のようなことではないでしょうか(想像なので, 本当のところは分かりません).

「安全であることをコンパイラが証明できる場合」は,「安全であることをプ
ログラマが証明できる場合」のサブセットに過ぎない.人間にとっては明らか
に安全なのに,コンパイラがそれを証明できない場合は多い.

プログラマには安全であることが明らかで,しかしコンパイラがエラーを出し
た場合,プログラマはアルゴリズムを変えるか? おそらくそんなことはしない
だろう.単に,コンパイラを満足させるために変数の初期化を付け加えるくら
いだろう.その変更によって,変更する以前よりも,何か安全になったか? そ
んなことはないだろう.

結局,安全かどうかをプログラマが判断していることに全く変わりはないので
あって,コンパイラのチェックを厳しくして「より安全になる」というのは幻
想に過ぎない.
_KM(Wed Oct 01 09:54:21 JST 2003)

 訳されてない一文 "I find that attitude disturbing in a program." (「あるでしょう。」と「私は、」の間に入る)というニュアンスからして,そんなところでしょう.

_K山(Wed Oct 01 09:57:26 JST 2003)

PITのインタプリタ生成系 Virtual Machine Builder の紹介 おもしろそうですね〜 行きたいけど,授業があるし. レポートお願いします(ぉ

_29(Mon)

夢のFFXI ベンチを動かしてみるが、2000。CPUがCeleron1.4GHz じゃ、ちょっと辛いかもね。

Radeon9600 を買ったつもりなんだが、プロパティでは 9600Pro と出てくる。はて?


http://www.namikilab.tuat.ac.jp/~sasada/diary/vote.cgi?mode=show&no=7#c-9

プログラムなのにMaybeはねーよなぁ。そんなノンキな。

ということですが、Haskell をよく知らないんでわかりません。でも、「こんな感じ」という文法でプログラミングできたらいいなぁ。

main(){
  ちょっとそれがあんな感じで、それを、そうそう、そんな感じ。
  多分、こうするんだけど、まぁ、適当に。
  でも、そこんところは上手くやっといてね。
  ちゃんと、計算してから結果ここに書いとくこと。わかった?
}

なぜか、C言語風にくくる。


2つの文字列の先頭から等しい文字列を抜き出す

def match_first(a,b)
  i = 0
  while a[i] and b[i] and a[i] == b[i]
    i+=1
  end
  a[0, i]
end

色々ない頭を絞ってみたんですが、何も考えずに書いたのが一番分かりやすそう。

def match_first(a,b)
  a.size.times{|i|
    return(a[0,i]) if a[i] != b[i]
  } and a
end

心情的には or と書きたい。

正規表現はよくわかりません。


なんか、誕生日が固まってるんですかね。おめでとうございます。


先日、重すぎてデキネー、と思っていたゲームが、Radeon9600 ではできるようになった。Direct3D をバリバリ使う2Dアドベンチャーゲームって、よくわからんなぁ・・・。


Radeonな幸せを体感できるのってなんかないかな・・・。


大規模プロジェクトに関わってる皆様。大爆笑してしまった。


いくつかの日記につっこみをさせてもらおうと思ったら、いくつかの理由で出来なかった。エラーだったり、つっこみページにいけなかったり、名前どうしよう、と思ったり ^^;

とりあえず、and を利用してるのは、改行の変わりに; を利用するより胡散臭くないからで、全然意味はないです。; のほうが速いんじゃないですかね。

東府中の自衛隊基地は、通学路なんですが、アンテナがあるなんて知りませんでした。今度見てみようかなぁ。

_とくめいきぼう(Mon Sep 29 06:10:19 JST 2003)

嫁さんがかつてプログラミングの仕事をしていたころ、どうにも向いていない後輩に指導をしたことがあるそうな。

あるプログラムの誤りを説明していたとき、後輩(女性)は理解しようとしばらく懸命に努力した後に顔を上げ、必死の面持ちで、 「『何となく』じゃダメなんですか?」 と聞いたそうな。

嫁さんは、 「…ダメなのよ。」 と答えたらしい。

もう何年も前のこと。 その後輩の行方は杳として知れない…かどうかは知らない。

(Maybeで思い出しました。でも、HaskellのMaybeって別に『何となく』じゃないけどね。McCarthyのAMB演算子のほうがよっぽど…)

_ささだ(Mon Sep 29 20:58:46 JST 2003)

 奥様はプログラマ。

_28(Sun)

おごってもらっちゃって、どうもありがとうございました。


CVSweb を試すが、annotate はできるが download が出来ない。うーん、なんでだろ。

わかった。

Error: Unexpected output from cvs co: cvs [checkout aborted]: Cannot check out files into the repository itself 

だったのだけれど、cvsweb.cgi を置いたのが、CVSROOT 以下だったからか。うーむ。

パスワード入れて、終り。なかなか壮観。


CVSweb で見ると、いい加減につけてきたログがダメダメっぽい。というか、複数ファイルコミットして一行ログ、でやってきたので、ログの意味が無い。

作業したら、1ファイルづつコミット、面倒なんだよな。挫折していた xyzzy の cvs-mode を試してみようかしら。


そういえば、CVSリポジトリって、用途にごとに複数用意するもんなんでしょうか。今、ディレクトリ掘って分けているのだけど。rb/nantoka とか piece/nantoka みたいな。


while true
  begin
    eval('break')
  ensure
    p 'ensure'
  end
end

このコードは、eval 抜きで break したのと同様の動作をしますが、こうあるべきなんでしょうか。それとも、こんなところまで面倒見なくてもいいんでしょうか。


と思ったらcvs-modeダウンロードできないのね(Nasal Daemon)。しかし、凄いページだ。


ビデオカードを買い換えるため、FF11 をやってみたいなぁと思うのだけど、やる時間があるかは相当疑問。積みゲーにするにはちと高いし。


秋葉原にきております。東洋という、喫茶店から無線Lanでつないでおります。いやー、便利な世 の中になったもんだ。

しかし、さすがにこういう喫茶店。聞こえてくる会話はアキバ系。こんなところでノー トPC広げてこんなこと書いてる私も私ですが。

家族用のPCのHDDが壊れたので、ちっちゃいの買おう、とか思って来たんだけど、なぜ か120GB HDDを買ってしまう。

あと、結局Radeon9600 買って、保険に G200 の中古。

_こーのいけ(Sun Sep 28 03:44:56 JST 2003)

 tar.gzを作るための権限が無いのでは?

_ささだ(Sun Sep 28 04:03:37 JST 2003)

 と、いうオチでした。 -p なのにディレクトリ選ぶのは、うーん。

_匿名希望(Sun Sep 28 16:03:03 JST 2003)

 アーカイブからcvs-mode落とせませんか。

_ささだ(Sun Sep 28 17:41:11 JST 2003)

 "Not Found" と言われてしまいました>cvs-mode

_fukumori(Sun Sep 28 20:22:06 JST 2003)

 実はお昼頃にアキバにいました。白色LEDのペンライトを買ってすぐ帰りましたが…

_shudo(Sun Sep 28 22:16:24 JST 2003)

 オヤヂの欲望渦巻く街 アキハバラ

_匿名希望(Sun Sep 28 23:26:09 JST 2003)

 cvs-mode-0.1.9.tar.gz なら落とせるようです。pre5とかpre7を落とそうとしてませんか?

_ささだ(Mon Sep 29 00:08:45 JST 2003)

 あー、ほんとだ。すみません、離れていたので気づきませんでした>0.1.9

_27(Sat)

寝坊したので今から行きます。

_n????n(Sat Sep 27 13:26:10 JST 2003)

 まってるわよ。ところで、あの娘さんどうした。

_26(Fri)

考えて見ると、「ほとんど」って、「ほとんど使ってない」なのか、「ほとんど Haskell」なのか、わからないな。前者のつもりだったんだけど。


n(略)さん、複数投票してないですか?(とか言ってみるテスト)。


初めて袋焼きそばを食す。カップ焼きそばより美味しいな。片付けが面倒だが。5袋200円。経済的にも優しい。

研究室に、もやしとかカイワレとか育てておけば、豊かな食生活に近づけることに気づく。さて、そんなに簡単に育てられるものだろうか?


うーん、もやしを育てるのって難しそうだなぁ。

カイワレはそんなに難しくないっぽい(カイワレダイコン)。熱ならPCがいくらでもあるしな。

んー、毎日水替えしないといけないのは面倒だなぁ・・・。


うぅ、飲みすぎた。

_25(Thu)

腹が減ったのでカップ焼きそばを作る。

ハックする。

悩む。

焼きそばを忘れる。

放置。

・・・。なんか、お粥を食ってる気分。


また学校に泊まる。泊まるもんじゃないな。作業効率が上がるわけでもなし。


やっぱり Haskell はマイナーらしいです。


携帯で DQ と FF ですか。凄い時代になったもんだ。

これ も携帯でできる時代がくるのかしら。

_24(Wed)

ちょっとドキドキしながら、ライバルである(勝手に決めてるし)Pybrid の処理速度と rucheme の処理速度を比べてみました。

・・・勝った!(勝負ナノカヨ)

さすがに、バイトコードコンパイルまでして速度で負けたら悲しすぎますから。


課題としては、「元のソースの情報が全部消えてる」ことか。これは困ったかもしれない。どうしてくれよう。


Scheme 使ってる?。意外と使ってる人は多いことがわかった。


理系のための恋人

まずは「疑惑」の解消から

こんな脳みその使い方したことがないなぁ...。

この記事の隣に「CPUの創りかた」の広告が載っているのに爆笑した。


飯を食ったら眠くなった。ダメ生活。

さて、こんどの投票の結果がどうなるか楽しみです。


なんか、某アレが進展したらしい。この間、「遅れたらどうするの?」って聞いたらキれられた(守るっつったら守るって感じで)ので、きちんと期限を守るのかと思ってたら、案の定2ヶ月遅れてるし。これだけ色々裏切られて、まだ続ける人の気が知れないが、まぁ、頑張ってください。皮肉ではなく、完成を楽しみにしてます。これでも、この作業に相当の時間を割いていたので。

_KM(Wed Sep 24 10:17:28 JST 2003)

 文献探しは NACSIS WebCat が便利.私は中央大学に出向いて判例のマイクロフィルムからハードコピーを取るという楽しい体験をしたことが...( ← 自分トコの図書館から紹介状をもらって行くのが吉 )

_23(Tue)

お嬢様の部屋。うーん、私の知らない世界だ(知ってたらそれはそれで問題だが)。

萌々(もも)ちゃんはどうかと思う。苗字云々よりも>あひる


The Design of an Optimizing Compiler は、農工大図書館で探したけど見つかりませんでした。また、東工大図書館に行ったときに覗いて見たんですが、なかったようです。探し方が悪かっただけかもしれませんが。残念です。


また学校に泊まってしまった。いろいろと終わらない。うーん。

腹が減った・・・。カップ麺はもう嫌だ。私の体の半分はカップ麺で出来てるだろう、多分。


先日買った500円の古本が、非常に有用であることがわかった。英語の仕様読まんと・・・と思っていたのが日本語できっちり書いてある。非常に嬉しい。


先生、妹増量ってどういう意味ですか。僕にはよくわかりません。


前田さんの指摘から。ruby イテレータの展開は可能か。不可能か。可能ならどのようにすればよいか。どのような制約が付くか。不可能と言ってしまうのは、多分簡単なんだろうけれど。

動的コンパイルなら何か出来そうな予感。


腹が減ったので家に帰ろう。全然終わってない。とてもまずい。


ダメアリー。

なんか駄目な話をしていて、昔のゲームを思い出した。おもしろい麻雀ゲームはないかねぇ、って話なんだけど。

わくわく麻雀ぱにっく、と言って知っている人はどれくらいいるんだろうか。多分誰も知らないだろうから、書けるわけだけど、あれは面白かった。何がってあの馬鹿さが。なぜそこで麻雀、という理不尽さがたまらなかった。今はなきフォアナインです。

で、フォアナインといえば、GAOGAOシリーズです。あれはとても面白かった。一作目がWindowsに移植されていたのを今日知りました。2年前らしいですが。あれ、きちんと全部出せば、今でも面白いと思うんですけど、どうですかね。冒険活劇は流行らないのかな。作るのは無茶苦茶大変だろうけど、ああいうゲーム、またやりたいなぁ。Windows できっちり作り直したら、またやりたい作品の一つ。ああ、昔のゲームは面白かった。

というわけで、最近の麻雀ゲームは、真面目でいけません。もっともっと馬鹿なのがやってみたいところです。Active も、幻想曲の最新版でも出してくれないかね。3は麻雀ゲームの最高傑作だと思うんだけど。是非あれを越えていただきたい。麻雀ゲームは、PC98時代のほうが面白かったな・・・。

と、ここの読者層には絶対わからないであろう話を書いてみる。


まぁ、こんなことを考えている、だめな休日。


Design and Implementation of Object Oriented Virtual Machines。これって、大学の専攻? それとも授業科目? 後者かな。いいなー、こんな授業がある学校。

でも、最近日記(その他)で色々教えてもらえてるからな。実は凄く贅沢かもしれない。ありがたいことです。

そうか、半年かけてOOなVM作るって授業なのか。なるほど。


TOSレジスタを入れたらほんのちょびっとだけ速くなった。ほんのちょびっと。

だいたい、rucheme normal より2倍ちょっと速い。次はオペランド複合を試してみるか?

_6(Tue Sep 23 15:51:03 JST 2003)

 たぬきの皮算用、なかなか馬鹿でよろしいかと

_22(Mon)

Excite エキサイト : サーチストリーム>サーチストリーム。やばい。楽しい。なんか、駄目な単語が見えたりするんですが。


一応、ruby での効率のいい命令ディスパッチを考える。

       user     system      total        real
   4.906000   0.016000   4.922000 (  5.000000) # __send__ symbol
   5.188000   0.000000   5.188000 (  5.328000) # __send__ string
   6.765000   0.016000   6.781000 (  6.891000) # case bytecode; when N; method
   4.047000   0.031000   4.078000 (  4.156000) # method

最後のは、まぁ参考。Rubyじゃ無理だし。

やっぱり、 __send__ symbol で決まりかな。

ん、計測のオーバーヘッドが結構あるか。


マクロ以外の primitive な式は実装おわり。次は peephole 最適化で遊ぶか。自己末尾再帰最適化を行うとき、ジャンプにしたいけれど、自己末尾であるかどうかを判定する方法がわからない。アドホックにやってしまうか?


[..].each{|e, i| ...} ってやると、勝手に each_with_index になってくれると嬉しいな。


最後に、到達不可能な部分を削るようなものを作ろうとしたら、私はフローグラフを作ったことがないことに気づく。はて、どうやるんだろう。いや、頑張ればできるだろうけど、どうやれば楽ができるか。


ある文字列変換メソッド trans が、次のようなのだったとき、

def trans str
  str.gsub(re1, str1).gsub(re2, str2). ...
end

逆変換メソッドを簡単に用意する方法はあるか。変換の対をデータとしてもっておいて、逆から変換するメソッドを定義するメソッドを書けばいいだけの話か。


青木峰郎さんの日記の「本日のリンク元」(の検索キー)を見ると、いかに青木さんの日記が多彩な話題を取り扱っているかがわかる。

なんとなく風俗系に偏っている気もする。全裸ってなんだろ。

そういえば、聞こうと思っていたことを忘れていた。今度聞こう。


学校に来て、PCのスイッチを押したら起動しない。焦る。無茶苦茶焦る。すげーー焦る。で、結局ビデオカード(G200)の不調だったらしい。今はオンボード。すげーショボイ。今週末にでも買いに行かないと・・・。金ないっちゅうのに。


SPAM が一日一通だったのが、10通くらい着てる。うーん。


うーん、evaluator とあわせてみたら、全然動かない。ダメダメ。

うーん、最初から命令を抽象的に書いてしまったのが敗因か。あと、形式的に書くとスゲーデバッグしずらい。


うーん、バイトコード化しても、2倍くらいにしか速くなってない。ショック・・・。

関数フレームの扱いが非常に不味いというのが一つ。5個も関数呼出し毎に退避してりゃ、そりゃ遅いかも。


副作用の無いマウスパッド n(言わなくてもわかるので略)さんに、マウスパッドを頂きました。これで副作用のある言語をバリバリ書きたいと思います。


しまった! shiro さんの、あの「研究開発」Tシャツは写真で撮っておくべきだった!(もちろん shiroさんも)


事故は、ある日突然に。。怖いなぁ。

_まえだ(Mon Sep 22 12:13:06 JST 2003)

 到達不能…jump, returnの後、ラベルまで消す(参照されないラベルは消しておく)。末尾再帰…callの次がreturnなら(returnにラベルが付いていても可)callをcall-tailに変える。known local function (もともとcall-local)ならjumpに変える。

_ささだ(Mon Sep 22 12:21:35 JST 2003)

 まんま前田さんのパクリで末尾再帰はやりました。そのとき、

call
return

=>

call-tail
return

に変換したんですが、return が残ってしまった。で、return を何も考えずに消すと、他がその return を参照している可能性があって、きちんとフローグラフ作って他の影響がないことを確認してから消さないと駄目なのかなぁ? と。

call
**label:
return

のときは、return は消さない、というだけでいいのかな・・・。まぁ、余分な return があってもなくても、実行には関係ないんですけど。なんかかっこ悪くて(あと optimization には邪魔になるか)。

あと、フレームの関係(スタックはヒープに取るようにしました)で、call-local => branch の変換がまだ出来ていないです。これは凄くやりたいんですが。

_ささだ(Mon Sep 22 12:55:29 JST 2003)

 あと、br の飛び先が return or tail-call だったら、そいつに変えるってのもやりました。

_まえだ(Mon Sep 22 16:05:49 JST 2003)

peepholeについてはWulfらの"The Design of an Optimizing Compiler"が本当に面白くてためになるんですけど、古い本(初版1975)だからなあ…あ、amazon.comで古本は買えるなあ。 Schemeでは、

(defpeep tail-merge2 tail-merge2-count (m n tag)
  :input ((CALL m n)
          (LABEL tag)
          (RETURN))
  :output ((CALL-TAIL m)
           (LABEL tag)
           (RETURN)))
(defpeep elim-unreachable elim-unreachable-count (insn1 insn2 args)
  :triggers (BR RETURN CALL-TAIL)
  :input
  (insn1
   (insn2 . args))
  :if ((not (eq? insn2 'LABEL)))
   :output
  (insn1))
(def-jump-peep branch-chaining5 branch-chaining5-count
  (tag1) (tag2)
  :input
  ((QUOTE #F)
   (BR tag1))
  :jump-target tag1
  :target-input
  ((BR-FALSE tag2))
  :output
  ((BR tag2))
  :target-output
  ((BR-FALSE tag2)))

なんていうルールをたくさん書きました。

_ささだ(Mon Sep 22 18:40:37 JST 2003)

 このpeephole最適化のルールは、自動で最適化ルーチンに展開されるんですか?

_まえだ(Mon Sep 22 23:42:57 JST 2003)

1. パターンマッチして置き換える関数定義 2. それを表(キーは命令シンボル)に登録するコード 3. 統計(パターンがヒットした回数)を記録する変数定義 に展開されます。 メインルーチンは、

  fired = false;
  while fired do
    instructions.each { |i|
      peeper_list = table[i.opcode]
      peeper_list.each { |peeper|
        fired = peeper.try(i)
      }
    }
  end

みたいな感じ。

_21(Sun)

今日は停電だったようです。気が付いたら復活してた。


direct threadingの課題としては、いくつか。

  1. gcc しか使えない
  2. 例外との親和性
  3. C関数呼び出しの親和性

gcc しか、というのは、私が windows マンセー人間なので、やっぱり VC に対応させたいという話です。でも、switch に落とすのは悔しい。というわけで、IA32 アセンブラをシコシコ書かないといけないのかなぁ。

例外をどう実装するか、というのも一つの問題な気がします。命令複合とか考えなければ、そんなに難しくない気もしますが。命令複合の際、基本ブロックの融合(そこまでするんか)のとき、嫌な気がします。

C関数の呼び出しは... なんとなく思ってるだけですが、全然関係ないかも。


Scheme 処理系は、eval を再帰で書くと、普通の手続き型言語では call/cc などの実装で困るので、あんまりしないと思うんですが、コンパイラはガンガン再帰使っていいわけで。ちょっと書いてるんですが、結構楽ですね。へへへ。

昨日の飲み会で shiro さんが仰っていた「みんな自分の Scheme の処理系を作ってしまう」というのは、非常に納得させられる話です。


昨日の飲み会といえば、お話できない方がいらっしゃったのが残念でした。植松さんには CE についてとか、新井さんにはリファレンスについてとか。まぁ、次回があるか。

というわけで、次回もよろしくお願いします。


Symbol には singleton method を加えることができない。あるシンボルと、他のシンボルを区別したいときにはどうすればよいか。

シンボルを諦めるしかないか。アホだなー。


S式でパターンマッチさせる何かを書かないと駄目なのか。面倒だなぁ・・・。


ちょろっと作ったら、

((lambda (a) (+ a a)) 2)

=>
0000: push 2
0002: make_procedure 7
0004: call 1
0006: return
0007: vref 0 0
0010: vref 0 0
0013: gref +
0015: call 2
0017: return

なかなかの駄目っぷり。この状態から最適化を目指していいものか。んー。

目標は

push 2
dup
gref +
call 2
return

なんだろうが、難しそう。

0000: push 2
0002: br 7
0004: ..
0006: ..
0007: vref 0 0
0010: dup
0013: gref +
0015: tail-call 2

になら出来そう。ローカル変数を一個引くのがちっと面白くない。br 分も無駄なのか。でも、これ以上は面倒なだけか...。

_20(Sat)

雨。めんどうくさいな・・・。


RHG 読書会で内職。ダイナミックスレッディング direct threading vs switch vs C。

先に結果。誰か追試してもらえると面白いかも。

clock : 94586   // Direct Threading
clock : 533417  // Switch
clock : 47268   // C native

ソースコード。

#include <stdio.h>
#include <time.h>


#define NEXT() \
  goto *((void *)(codes[pc]))

//  printf("PC: %d SP: %d TOS: %d\n",pc, sp, tos); \


#define TEST_MAX 100000

#define DEBUGP 
//#define DEBUGP printf

int stack[0x100];
int bcodes[] = {
  0,TEST_MAX, // push TEST_MAX
  0,1, // push 1
  2,   // sub
  8,   // dup
  6,2, // br_true 2
  
  4, // return
};
void* codes[0x100];
void* ops[0x100];

int test_tc(int flag){
int pc = 0;
int sp = 0;
int tos;

  if(flag){
    ops[0] = &&inst_push;
    ops[1] = &&inst_add;
    ops[2] = &&inst_sub;
    ops[3] = &&inst_br;
    ops[4] = &&inst_return;
    ops[5] = &&inst_br;
    ops[6] = &&isnt_br_true;
    ops[7] = &&inst_br_false;
    ops[8] = &&inst_dup;
    
    ops[10]= &&inst_op_fusion_br;
    ops[11]= &&inst_dmy1;
    ops[12]= &&inst_dmy2;

    return 0;
  }
  tos = 0;
  pc  = 0;
  
  NEXT();
  
inst_push:
  stack[sp++] = tos;
  tos = (int)codes[++pc];
  DEBUGP("push => %d\n", tos);
  pc++;
  NEXT();

inst_dup:
  stack[sp++] = tos;
  pc++;
  NEXT();
  
inst_add:
  tos += (int)stack[--sp];
  DEBUGP("add => %d\n", tos);
  pc++;
  NEXT();

inst_sub:
  tos = stack[--sp] - tos;
  DEBUGP("sub => %d\n", tos);
  pc++;
  NEXT();

inst_br:
  pc = (int)codes[++pc];
  NEXT();

isnt_br_true:
  if(tos){
    tos = (int)stack[--sp];
    pc = (int)codes[++pc];
    NEXT();
  }
  else{
    tos = (int)stack[--sp];
    pc += 2;
    NEXT();
  }

inst_br_false:
  if(tos == 0){
    tos = (int)stack[--sp];
    pc = (int)codes[++pc];
    NEXT();
  }
  else{
    tos = (int)stack[--sp];
    pc++;
    NEXT();
  }
  
inst_return:
  sp--;
  return tos;

inst_op_fusion_br:
  goto inst_dmy2;

inst_dmy1:
  printf("dmy");
  NEXT();
  
inst_dmy2:
  printf("dmy");
  NEXT();
}

int test_sw(){
int pc = 0;
int sp = 0;
int tos;
  
  while(1){
    switch(bcodes[pc]){
    case 0: // push
      stack[sp++] = tos;
      tos = (int)codes[++pc];
      DEBUGP("push => %d\n", tos);
      pc++;
      break;
      
    case 2: // sub
      tos = stack[--sp] - tos;
      DEBUGP("sub => %d\n", tos);
      pc++;
      break;
      
    case 4: // return
      sp--;
      return tos;
      
    case 6: // if true
      if(tos){
        tos = (int)stack[--sp];
        pc = (int)codes[++pc];
      }
      else{
        tos = (int)stack[--sp];
        pc += 2;
      }
      break;
      
    case 8: // dup
      stack[sp++] = tos;
      pc++;
      break;
    }
  }
}

int test_c(){
  volatile int i;
  for(i=0;i<TEST_MAX;i++){
    // none
  }
}


int compile(){
  int i;
  int size = sizeof(bcodes) / sizeof(bcodes[0]);
  
  for(i=0; i<size; i++){
    codes[i] = ops[bcodes[i]];
    if(bcodes[i] == 0 ||
       bcodes[i] == 6 ||
       bcodes[i] == 7){

      i++;
      codes[i] = (void *)bcodes[i];
      printf("** %d\n", codes[i]);
    }
  }
  return 0;
}


#define MAX 0x7fff
//#define MAX 0x700


int main(){
  int i;
  clock_t t;
  
  test_tc(1);
  compile();

  // printf("ans => %d\n",test(0));

  t = clock();
  for(i=0;i<MAX;i++){
    test_tc(0);
  }
  printf("clock : %d\n", clock() - t);
  
  t = clock();
  for(i=0;i<MAX;i++){
    test_sw();
  }
  printf("clock : %d\n", clock() - t);

  t = clock();
  for(i=0;i<MAX;i++){
    test_c();
  }
  printf("clock : %d\n", clock() - t);

  return 0;
}

やっぱ private instance variable は欲しいなぁ。


飲み会 読書会、相変わらず大変たのしうございました。

詳細はRWikiのページ(RHG読書会::東京 Reloaded)を。


prefetch ってなんだろう、と考えて、命令ごとに次の命令のアドレスをロードするようにした。

#define NEXT() \
  DEBUGP("PC: %d SP: %d TOS: %d PTR: %08X\n",pc, sp, tos, ptr); \
  goto *ptr;

#define PRE(n) \
  ptr = codes[pc + n]

...

inst_push:
  PRE(2);
  stack[sp++] = tos;
  tos = (int)codes[++pc];
  DEBUGP("push => %d\n", tos);
  pc++;
  NEXT();

ら、遅くなった。prefetch って、何を prefetch するのでしょうか。不勉強ですみません。

_まえだ(Sat Sep 20 21:48:11 JST 2003)

 誤: Dynamic 正: Direct

_まつもと(Sat Sep 20 22:48:57 JST 2003)

 prefetchしたら、test_tcはさらに最大2割速くなりました。

_ささだ(Sat Sep 20 23:17:26 JST 2003)

 がぁ、お恥ずかしい>ダイレクト

_まえだ(Sun Sep 21 00:47:56 JST 2003)

 Coppermineで、stack[sp]のかわりにポインタで*spとしたらtest_tcは1割ほど遅くなりました。そういうもの??

_まえだ(Sun Sep 21 01:21:20 JST 2003)

dynamic replicationの結果をシミュレートしてみました。 あんまり速くならないね。test_tcは、もともとBTBミスがほぼ皆無だから。

include <stdio.h>
#include <time.h>


#define NEXT() \
  goto *((void *)(codes[pc]))

//  printf("PC: %d SP: %d TOS: %d\n",pc, sp, tos); \


#define TEST_MAX 100000

#define DEBUGP
//#define DEBUGP printf

int stack[0x100];
int bcodes[] = {
  0,TEST_MAX, // push TEST_MAX
  9,1, // push' 1
  2,   // sub
  8,   // dup
  6,2, // br_true 2

  4, // return
};
void* codes[0x100];
void* ops[0x100];

int test_tc(int flag){
  int pc = 0;
  int sp = 0;
  int tos;

  if(flag){
    ops[0] = &&inst_push;
    ops[1] = &&inst_add;
    ops[2] = &&inst_sub;
    ops[3] = &&inst_br;
    ops[4] = &&inst_return;
    ops[5] = &&inst_br;
    ops[6] = &&isnt_br_true;
    ops[7] = &&inst_br_false;
    ops[8] = &&inst_dup;
    ops[9] = &&inst_push2;

    ops[10]= &&inst_op_fusion_br;
    ops[11]= &&inst_dmy1;
    ops[12]= &&inst_dmy2;

    return 0;
  }
  tos = 0;
  pc  = 0;

  //NEXT();

 inst_push:
  stack[sp++] = tos;
  tos = (int)codes[pc + 1];
  DEBUGP("push => %d\n", tos);
  pc += 2;
  //NEXT();

 inst_push2:
  stack[sp++] = tos;
  tos = (int)codes[pc + 1];
  DEBUGP("push => %d\n", tos);
  pc += 2;
  //NEXT();

 inst_sub:
  tos = stack[--sp] - tos;
  DEBUGP("sub => %d\n", tos);
  pc++;
  //NEXT();

 inst_dup:
  stack[sp++] = tos;
  pc++;
  //NEXT();

 isnt_br_true:
  if(tos){
    tos = (int)stack[--sp];
    pc = (int)codes[++pc];
    NEXT();
  }
  else{
    tos = (int)stack[--sp];
    pc += 2;
    //NEXT();
  }

 inst_return:
  sp--;
  return tos;

 inst_add:
  tos += stack[--sp];
  DEBUGP("add => %d\n", tos);
  pc++;
  NEXT();

 inst_br:
  pc = (int)codes[++pc];
  NEXT();

 inst_br_false:
  if(tos == 0){
    tos = (int)stack[--sp];
    pc = (int)codes[++pc];
    NEXT();
  }
  else{
    tos = (int)stack[--sp];
    pc++;
    NEXT();
  }

 inst_op_fusion_br:
  goto inst_dmy2;

 inst_dmy1:
  printf("dmy");
  NEXT();

 inst_dmy2:
  printf("dmy");
  NEXT();
}

int test_sw(){
  int pc = 0;
  int sp = 0;
  int tos;

  while(1){
    switch(bcodes[pc]){
    case 0: // push
    case 9:
      stack[sp++] = tos;
      tos = (int)codes[++pc];
      DEBUGP("push => %d\n", tos);
      pc++;
      break;

    case 2: // sub
      tos = stack[--sp] - tos;
      DEBUGP("sub => %d\n", tos);
      pc++;
      break;

    case 4: // return
     sp--;
      return tos;

    case 6: // if true
      if(tos){
        tos = (int)stack[--sp];
        pc = (int)codes[++pc];
      }
      else{
        tos = (int)stack[--sp];
        pc += 2;
      }
      break;

    case 8: // dup
      stack[sp++] = tos;
      pc++;
      break;
    }
  }
}

int test_c(){
  volatile int i;
  for(i=0;i<TEST_MAX;i++){
    // none
  }
}


int compile(){
  int i;
  int size = sizeof(bcodes) / sizeof(bcodes[0]);

  for(i=0; i<size; i++){
    codes[i] = ops[bcodes[i]];
    if(bcodes[i] == 0 || bcodes[i] == 9 ||
       bcodes[i] == 6 ||
       bcodes[i] == 7){

      i++;
      codes[i] = (void *)bcodes[i];
      printf("** %d\n", codes[i]);
    }
  }
  return 0;
}

#define MAX 0x7fff
//#define MAX 0x700


int main(){
  int i;
  clock_t t;

  test_tc(1);
  compile();

  // printf("ans => %d\n",test(0));

  t = clock();
  for(i=0;i<MAX;i++){
    test_tc(0);
  }
  printf("clock : %d\n", clock() - t);

  t = clock();
  for(i=0;i<MAX;i++){
    test_sw();
  }
  printf("clock : %d\n", clock() - t);

  t = clock();
  for(i=0;i<MAX;i++){
    test_c();
  }
  printf("clock : %d\n", clock() - t);

  return 0;
}

_19(Fri)

というわけで、そろそろ帰ろう。


ツインズ7, 8話。やっぱりキャラクター違うよな。でも、資産があるって素晴らしいよな。しかし、毎回毎回入浴シーン、よくがんばってるなぁ。


MIDIといえば。昔 PC-98用に MIDIファイルを読んでシリアルを叩いてMIDI音源を鳴らすのを作った覚えが。懐かしい。最近では埃を被っている AG-10。サウンドカード内臓音源で十分なんだもんなぁ。

MIDIフォーマット、よくわかんないから見ながら解析してった気が。あれ、資料見ながらだったかな。どうやって作ったんだっけ。忘れたな、もう。


というわけで、今日もおでかけ。


考えてみると(考えなくても)スゲー貴重な体験。実はガクガクブルブルでした。

_KM(Fri Sep 19 09:35:36 JST 2003)

 MIDI そのものは,とにかく流せば OK だから,SMF (Standard MIDI File) の資料じゃないかな.それともシリアル受信しながら解析? MIDI の仕様書は池袋ジュンク堂だとデスクトップミュージック本の棚の端にあったような.

_ささだ(Fri Sep 19 10:04:10 JST 2003)

 いや、昔(高校時代)の話なんで。

_ささだ(Fri Sep 19 10:08:12 JST 2003)

 って、流せばオッケーじゃないでしょ、たしか。流すタイミングとか、ホストでコントロールするんじゃ? それとも、流せばシーケンサが勝手にやってくれたのかなぁ。

_KM(Fri Sep 19 12:30:04 JST 2003)

 MIDI には,直ちにノートオン/オフしろ,のようなメッセージしか (基本的には) ないので,ホストから送るタイミングとかは MIDI の外側で決めないと.っていうかそういう情報が付加されてるのが SMF (F は Format だったかも) なんだけど,SMF なファイルの拡張子はふつ〜 .MID だったから,SMF が MIDI そのものだと思われがちナノ鴨菜

_ささだ(Fri Sep 19 12:36:08 JST 2003)

 あー、なるほど。

_mput(Fri Sep 19 14:25:51 JST 2003)

 SMPTEタイムコードを送ることも(いちおう)できますよ。タイムコード送信だけで規格の転送速度(31250bit/s)をオーバーするんですけどね(これを回避するための涙ぐましい努力が……)。

_18(Thu)

今日ははじめての東工大。英語はきっとわかりません。


東工大

というわけで、英語わかりませんでした。というかね、日本人なんだから、日本語で質問してくれヨ(馬鹿)。いや、非常に聞きやすい英語だったと思うのだけど、脳ミソが付いていかなかった。結局わかったのは自分の知っているところだけだった。ヤレヤレ。

Parallel GC と Concurrent GC、よく違いがわからなかった。というか、パラのほうは説明してたような気がしたけど、コンカレントは説明してたのかなぁ・・・。

質問したかったのだけど、やっぱり英語に臆して出来なかった。やっぱり英語が課題だ。

松岡先生とか、千葉さんとか田浦さんとか。英語うますぎだよ。本当に日本人なんでつか? 聞き取れなかったんだもん。日本人英語は聞きやすいはずなのだけどなぁ。

というわけで逃げるように退散。


終わって、失意の中帰っていく途中、松岡研飯野さんに声をかけられる。SACSIS で居たのを覚えていてもらったようで、大変ありがたいことです。で、ご好意で松岡研のクラスタを見せてもらうことに。

松岡研クラスタ 松岡研クラスタ 扇風機がいっぱい。轟音。

いろいろ興味深いお話もお伺いすることが出来ました。非常によくわかりました。日本語だったし

  • 現在 TOP500 で大変
  • クラスタ計算機の計算時間は実は頼めば貸してくれるかも
  • S-Core をのっけようとしている(pm が使いたいらしい)
  • 現状は mpitch をそのままのせてる(それだけであれだけのものが動くってのも凄い)
  • Fault tolerant なクラスタシステムが結構頑張ってるテーマらしい
  • 特に何かを計算しよう、という目的はないらしい
  • 光スイッチはよく壊れるらしい
  • 電気は壊れないらしい
  • ミリネットはよくできてるらしい
  • ラックマウントPC 1台 xx円らしい
  • Opteron とくっつけるときは、ヘテロクラスタではなくホモなクラスタ環境として扱うらしい。
  • 64Bit で嬉しいのは浮動小数点演算が高速になることくらいらしい
  • やはり大規模クラスタには空調や電力など、室内設備が非常に重要らしい
  • というわけで、省電力でFTなクラスタが今の課題らしい
  • 他にも松岡研では UI/Java/Grid/Compiler などをやっているらしい
  • 丸山さんとかは海外に行っているらしい
  • というわけで、Java の GC の話を聞きに行ったのに、全然違う知識が増えてしまったらしい

Java な人に話が聞けなかったのはちょっと残念かも。研究室の人たちがみんな忙しそうに働いていたのが印象的だった。お忙しい中、いろいろ解説していただいてどうもありがとうございました m(__)m

松岡研は、見学、質問 welcome だそうです。事前にメールがあれば、準備もしてくれるそうです。興味のある方は是非。


Java については OpenJIT をなぁ。あの辺の技術の詳細が、やっぱり聞いてみたいぞ。


山城さんの研究室とか、聞いとけばよかったな。一応ぶらぶらしてみたんだけど、見つけられず。


帰りに東工大図書館を覗いてみる。和書、意外に少ない。これなら農工大工学部図書館のほうが豊富かも。書籍は研究室の中でがめてる確保してるんだろうな。洋書はそれなりにあった。けど古かった。

そういえば、大岡山駅を降りたとき、一生懸命地図を探したんだけど、みつからなかった。しょうがないから人に聞くかぁ、とか思ったら目の前にあった。あれはやばいくらい近いだろ。しかも、学校広いし。


あまりに眠いので4時間ほど寝てしまった...。脳みその中GCしてくれてるような気はするんだが、きっとバグ持ちに違いない。

しかも風邪ひいたっぽい...。


RHG に shiro さんが・・・。これは楽しみ。


というか、明日という日程はそういう意味か・・・。どうなのかなって思ってたけど。楽しみです。

うーん、明日はちゃんと髭そってスーツ着ていかないとだめかな...。社会人のコスプレで...。

_shudo(Thu Sep 18 11:56:02 JST 2003)

 東工大は行かないことにしました。遠いです。直後の都内での別件と、微妙に時間がかぶってるし。

_山城(Thu Sep 18 18:55:28 JST 2003)

 いらしてたんですねー。研究室のプリンタ修理の件で研究室に常駐しておりました。今度は是非。

_shudo(Thu Sep 18 23:59:22 JST 2003)

 田浦さんからメールの返事をもらえず、出張でもしてるのかな〜、と思ってたんですが、ちゃんと日本にいらっしゃる

_17(Wed)

というかね、実行時の命令複合って、Rava で試していたアプローチだったのですよね。

単純にくっつけただけじゃ(Ruby は最適化やらないから)ダメダメなので、アドホックに(少ないパターンについて)組み合わせるものを作って。あれをもっとシステマティックに行うようにするって話なんだろうなぁ。


漆塗りマウスのHomePage(simpl-ml)。スゲー。欲しい。


VM上での分岐予測って、意味あんのかなぁ? よく読んでないけど・・・。


簡単な例。

=ipush arg1
push(arg1)

=iadd
a = pop()
b = pop()
push(a+b)

----

ipush 10
ipush 20
iadd      ==> ipush_ipush_iadd arg1, arg2


=> (1) direct concatenate
push(arg1)
push(arg2)
a = pop()
b = pop()
push(a+b)

=> (2) optimized concatenate
push(arg1 + arg2)

VMgen では、直接くっつけたのしかやらないから、余計なスタック操作が残るじゃーん。とか思ってたんですが、gcc に食わせて、最適化させるのですねぇ。コピー伝播でこれが最適化されるとは・・・。ズルイゾ。

最適化が十分でないコンパイラを使うとき、このアプローチは使えないよなぁ、多分(とか言ってみる)。

=ipush arg1
arg1

=iadd
pop + pop

こう書かせれば、さっきの最適化はできるような気がするなぁ。

というか、vmgen の記述方法はまんまこれなんですね・・・。

なんか、正規順序でリダクションしてくような処理系にすれば、最適化が容易に出来るような気がしてきた。ほんとか? なら、S式で命令記述作ってみるかな?

(define-inst (ipush arg1) () arg1)
(define-inst (iadd) (i1 i2) (+ i1 i2))
(define-inst (isub) (i1 i2) (- i2 i1))

ipush 10
ipush 20
iadd
ipush 100
isub

(define-inst (ipush_ipush_iadd_ipush_isub arg1 arg2 arg3)
			 (ipush arg1)
			 (ipush arg2)
			 (iadd)        ;; reduction
			 (ipush arg3)
			 (isub))

(define-inst (ipush_ipush_iadd_ipush_isub arg1 arg2 arg3)
			 (+ arg1 arg2)
			 (ipush arg3)
			 (isub)        ;; reduction
			 )

(define-inst (ipush_ipush_iadd_ipush_isub arg1 arg2 arg3)
			 (- (+ arg1 arg2) arg3))

正規順序関係ないし・・・。つーかこれリダクションじゃないやん。

って、これは逆アセンブルしてるだけじゃん・・・。


オペランドを引数、じゃなくて、スタックの値を引数にとることにしてみよう。


rava をこれで書き換えてみようかなあ。面倒だなぁ・・・。


というかね、私の修論研究って、一応 SMTアーキテクチャプロセッサを有効に活用するためのシステムソフトウェアなんですよ。


頭がふらふらする。風邪かな・・・。

バイトしよ、バイト。全然終わってないぞ・・・。


今日の図書館。

  • Python テクニカルリファレンス
  • プログラミング言語 Standard ML入門
  • コンパイラの構成と最適化

うーん、中田先生のこの本を借りたのは何度目だろう。

bit、読みました。なんか、知ったような単語が既に 80年代のトピックなのですね...。

図書館の bit 、ページが切り取られている部分があった。どこにでも馬鹿はいるもんだ。やれやれ・・・。


前田さんの命令セットを S式にしたらこんな感じ?(仕事しろよ俺...)

- (get-arg n) は、予約語とする。
- body 中の操作名は、実装依存の処理と変換するとする。
  要するにそれに相当する ruby scriptに。
- define-inst、defin-inst/ctrl の引数の最初は、オペランドの数。
  オペランドは (get-arg n) で n番目のオペランドを取得。


* 返り値を push する

;; (vref index depth)
(define-inst (vref 2)
             (get-local-env (get-arg 1) (get-arg 2)))

;; (gref symbol)
(define-inst (gref 1)
             (get-top-env (get-arg 1)))

;; (vset index depth)
(define-inst (vset 2 val)
             (set-local-env (get-arg 1) (get-arg 2) val))

;; (gset symbol)
(define-inst (gset 1 val)
             (set-top-env (get-arg 1) val))

;; (quote const)
(define-inst (quote 1)
             (get-arg 1))

;; (discard n)
(define-inst (discard 1)
             (let ((x (pop)))
               (dotimes (- (get-arg 1) 1) (pop))
               x))

;; (make-procedure label)
(define-inst (make-procedure 1)
             (make-procedure (get-arg 1)))


* 最後に push しない

;; 環境を一個中に作っちゃう
;; (make-env n)
(define-inst/ctrl (make-env 1)
                  (make-env (get-arg 1)))

;; (return)
(define-inst/ctrl (return 0)
                  (pop-control))

;; (br label)
(define-inst/ctrl (br 1)
                  (jump (get-arg 1)))

;; (br-false label)
(define-inst/ctrl (br-false 1 cond)
                  (if (not cond) (jump (get-arg 1))))

;; (br-true label)
(define-inst/ctrl (br-false 1 cond)
                  (if cond (jump (get-arg 1))))

;; (call narg)
(define-inst/ctrl (call 1 proc)
                  (if (c-proc? proc)
                      (call-c proc (get-arg 1))
                    (push-control (get-arg 1))))

;; (call-tail narg)
(define-inst/ctrl (call-tail 1 proc)
                  (if (c-proc? proc)
                      (call-c proc (get-arg 1))
                    (set-control (get-arg 1))))

;; (call-local label narg depth)
(define-inst/ctrl (call-local 3)
                  (push-control-local (get-arg 1)
                                      (get-arg 2)
                                      (get-arg 3)))
;; (pop)
(define-inst/ctrl (pop 0)
                  (pop))

;; (check-stack n)
(define-inst/ctrl (check-stack 1)
                  (check-stack (get-arg 1)))

ちょっと修正。make-procedure の nvars, nargs, has_rest? が何を表すのかわかんなかったので省く。またちょっと修正。set! 系を付ける。ruby ではリファレンスを作るとやっぱり処理が遅いので、arrayのリストでいいや、と。それとも、hash のリストにしようかな。どうしようかな。make-env も追加。let を変換して利用。これは、もしかしてダメな方法かもしれないなぁ。もうちょっと考えよう。

こいつから、rubyソースへの変換はきっと楽なんだろう。楽なことにしておく。rucheme/c は、全てこいつらにコンパイルするようにしてしまうか。んで、こいつらから、動的に複合命令を作っていく。まとめられるだけまとめてしまえばいいだろう。これなら簡単に出来そうだ。

やっぱり ruby は eval が使えていいなぁ。はっきりいって、汎用的アプローチじゃないけど。分岐の部分で工夫が出来そう。


ruby では、switch & goto な手は使えない。case/when では遅すぎるし、そもそも goto に相当するものが無い。なので、call threading にするしかない(と私は思ってる)。とすると、br がもうちょっと纏められる形になると、もっと良いのか。

って、なんか ruby への translator になってきた・・・。


「優勝しないタイガースを愛する会」、その夜解散 。うーむ。asahi.com もこういう記事書くんだ。


勢い余って、上記S式から、VMループを処理するような何かを書いてしまった。やることはテキスト処理なので、Ruby が楽だなぁ、やっぱり。S式弄りでも。


じゃぁ、雑誌記事楽しみにしてます。うーんと恥ずかしいやつ :)


シリーズ Vol.36 THE 娘育成シミュレーション。2048年つったら、すでにリアル娘も巣立ってるんじゃないか。いや、凄い可能性の低い未来ですけど。


なんか、この表記なら、scheme上で実装するのが楽そうやなぁ。Java用を書いて、Schemeで動かしてみようか。しかし、200命令書くの面倒くさいんだよな・・・。

うーん、S式操作は scheme でやったほうが、やっぱ楽かも。rucheme/normal でここだけはやるようにしようかなぁ・・・。

VM駆動部分はできたので、肝心の compile 部分を書かなければ。って、ほかにやることあるだろ、俺・・・。

_KM(Wed Sep 17 10:47:32 JST 2003)

 私みたいなダメ人間を尊Kしちゃいけません.複合命令については RISC が流行る前(つまりヘネパタ以前)の文献に結構基本的なコトが載ってるように思います.1980 年に bit 別冊で出てる「ダイナミック・アーキテクチャ」は,眺めるといいかも.たしか,農工大図書館では bit のバックナンバーと一緒になってたような.

_ささだ(Wed Sep 17 11:05:39 JST 2003)

 尊Kするしないは置いといて、飲み代はよろしく。

_まえだ(Wed Sep 17 11:51:24 JST 2003)

 「VM上での」つーか、VMを実行するx86とかAlphaとかが激しく分岐予測ミスするので、これをなんとかしようという話。threaded codeの実行時間の半分以上が分岐予測ミスペナルティだとか。

_ささだ(Wed Sep 17 12:00:10 JST 2003)

 あぁ、そうだったんですか。なるほど。やっぱりちゃんと読まないとダメですねぇ。

_shudo(Wed Sep 17 12:08:26 JST 2003)

 http://www.shudo.net/publications/klab-200106/ 前田さんに教えてもらったりなんだりで知ったいくつかのインタプリタの性能向上テクニックをスライドにしたものです。なんとか threading とか、stack caching とか。スライド 12枚目に、dispatch 処理部を VM 命令間で共有しないことで分岐予測ミスが減るんじゃないか? と書いてしまったのですが、ほんとでしょうか。

_まえだ(Wed Sep 17 16:41:18 JST 2003)

 減ります。分岐命令処理部のif文のthenとnextでディスパッチ命令を分けるだけでも減ります。vmgen論文の5.4節参照。

_ささだ(Wed Sep 17 16:57:03 JST 2003)

 その節を読んで、やっとBTBの意味がわかりました。

_新潟のS(Wed Sep 17 20:09:39 JST 2003)

 大堀先生の本の解答集ってないでしょうかね。独学で解答例がないとつらいです。

_ささだ(Wed Sep 17 20:18:39 JST 2003)

 じゃぁ、今度MLで読書会やりますか、新潟で(ぉ。

_新潟のS(Wed Sep 17 23:03:32 JST 2003)

 いいっすね〜。SICP読了後はSMLに戻るつもりです。

_n???n(Thu Sep 18 08:33:02 JST 2003)

 Haskell にしましょうよ。> 新潟のSさん

_新潟のS(Thu Sep 18 23:05:41 JST 2003)

 間をとって、LazyMLってのはどうですか?> n????n   ん、?は4つかな。

_ささだ(Thu Sep 18 23:57:38 JST 2003)

 Lazy な ML => Haskell ってイメージがあるんですが、ダメですか、こういうの。

_16(Tue)

日記で、けっこう面白い議論になっているのがあるんだけど、私の日記では1日しか(表に)表示しません。これってもったいない気がするんだけど、どこかで議論だけを保存させてくれるような wiki って無いものでしょうか。うちでは wiki 禁止らしいんで・・・。

多分、もりあがってるのってVM実装の話だと思うのですが(もう忘れてるらしい)。


alternative第二段。

スタック一本 vs スタック一杯。とりあえず、メソッド(関数)フレーム用制御スタックを用意するか、しないかってところで。

私は、スタック一本のほうが次の点でいいと思っていました。

  • スタック用メモリ管理が一箇所でいい
  • スタックポインタがマシンレジスタに格納されるかもしれない

でも、制御用スタックを分けることで、末尾再帰が簡単になるようです。また、フレームを積む時期がフレキシブルになるような気がします。

さて、どっちが良いか。速度よりも(言語仕様との兼ね合いによる)実装のしやすさにかかるのかもしれないな。これは。


VM命令構成法。基本命令が n 個ある。この n 個が2個つながるようなパターンは n * n 個ある(ただし、分岐命令などの後には命令はつかないこととする。分岐遅延なんて勿論なし :-P)。n * n 個を手で実装するのは大変である。幸い、n個の命令は既に実装した。ならば、その n 個の命令を利用して、それが2つならんだパターンを楽に作ることが出来ないだろうか。

単純に並べると、まぁ出来なくは無いが、最適化したものではない。基本命令処理を並べたものを勝手に最適化してくれるような、メタ命令記述があればよい。これを繰り返せば、最初に n個の処理プリミティブを書くだけで、基本命令を 1〜m個並べた Σ n ** i (1<=i<=m)個の命令を作ることができる。

さて、こんなメタ記述は可能か。

Optimizing direct threaded code by selective inliningの手法は、ただくっつけているだけなような気がする。元になるアセンブラが何処からやってきたのか不明(fig.8)。また、アセンブラを利用すると、移植性が嫌な感じ。

まぁ、べらぼうに沢山乗っけても、I-cache に乗らなくなりそう。一つ5word だとして 20byte、4KB I-cache として、400命令くらいが上限かな。

んで、実際に動かしてみて、つかわねー命令を統計とって、勝手に消してくれんの。きっと楽な世界。

もちろん前田さんの論文を自動化できないか、って話です。

スタックマシンを前提とすれば、そんなに難しい話では無さそう。自分では余裕が無いのでやらないだろうけど。

あ、特定オペランドの命令化を忘れていた・・・。

そうか、頻出命令(or 命令+頻出オペランド)を抽出するのと、命令融合の自動化は別の話か。


とか、偉そうに書いたけど、誰か既にやってそうだな。

_たむら(Tue Sep 16 16:31:11 JST 2003)

 HikiFarmを用意するとか。http://www.namaraii.com/hiki/?HikiFarm

_ささだ(Tue Sep 16 16:41:21 JST 2003)

 wiki が駄目なんで、hikifarm も駄目だと思うのです。

_shudo(Tue Sep 16 19:40:56 JST 2003)

 PicoJava が instruction folding を動的にやってたなあ、と思い出した。> 複数命令をつなげたものを最適化

_shudo(Tue Sep 16 19:43:11 JST 2003)

 要は、命令セットを自動生成、もしくは、自動的に最適化したい、ってことなんだと思います。「最適」の基準が山ほどありそう。命令数、インタプリタでの性能、コードサイズなどなど。

_shudo(Tue Sep 16 19:48:01 JST 2003)

 中西さん(九大)が何年か前に組み込み向けにやってた研究を思い出した。>命令セット自動最適化 コードサイズを小さくするために、命令に対応するビット列をハフマンエンコーディングで作る、ってやつ。

_shiro(Tue Sep 16 20:16:28 JST 2003)

 東工大の脇田さんが去年のILCでVMの記述言語の話をしてました。インストラクション仕様の記述からVMコードが自動生成されるというものです。命令の統合は自動じゃないけど、ちょっとした指定でできたような。いろいろ試してみるには便利かもしれません。

_み(Tue Sep 16 20:48:17 JST 2003)

 中西さんのは論文になっていたような...新しいシステムソフトの潮流だったかな。コードサイズがひとつの尺度。このテのって、何命令まで見るか、オペコード、オペランド、果ては分岐までやりだしたりして。

_まえだ(Wed Sep 17 01:03:26 JST 2003)

Ertlらのvmgenは、複合命令の最適化をCコンパイラに任せてます。実行時に最適化するのはむずいなあ。Etrlらの新しい論文だと、複合命令の効果としてはBTBミス削減が大きいらしい。あと、かなり無節操にインタプリタを大きくしても、キャッシュミスは問題にならないらしい。(素朴なコンパイラ並みの速度が得られて、移植には1時間とか書いてある…)

_ささだ(Wed Sep 17 08:07:40 JST 2003)

 東工大脇田さんの論文、のことでしょうか。中西さんのは見つからず。ところで、スタック操作って、C言語で最適化されるものでしょうか?

_ささだ(Wed Sep 17 08:08:38 JST 2003)

 最適化は、まぁ、速いのが正義っていう方針で。

_ささだ(Wed Sep 17 08:46:29 JST 2003)

 命令複合のために抽象化されなければならないのはオペランドとスタック操作だと思っています。なので、その辺をごにょごにょしてくれるようなシステムがあれば・・・。全部形式記述にしなくてもいいと思うんですが、甘いですかね。

_15(Mon)

Gauche の disasm の結果を見ていると、Gauche VM の命令体系では、値をスタックではなくレジスタに格納しているように見える。ScmVMRec->val0 かな、多分。

まつもとさんの未踏の報告書でも acc というレジスタを用意していた。

JavaVM は、全てスタックに対する操作。SmallTalk-80 も、多分スタックに対する操作になっていると思う。

どちらを取ればいい、ということに関する、定量的な評価って、どこかの論文でやってるんでしょうか。調べようにも、どういう単語で調べていいかわからないので。

これに関しては、結構悩んだんだけど、どっちがいいんだかよくわからない。結果を使いまわすような言語の場合、レジスタへ対する演算のほうがいいんだろうか。あと、レジスタマシンへの応用が楽になるのかもしれないなぁ(結果格納レジスタのリネーミングを頑張ってみたり)。あと、関数(メソッド)リターンのコストが安くなったり・・・。

CPU でも、arg用、return用レジスタってあるしなぁ。RISC じゃ。

なんか、レジスタにしたほうがいいような気がしてきた。ひよるか。


真面目に得失を考えてみる。命令の結果がスタックに格納されるか、レジスタに格納されるかの対比。

■レジスタ

  • ○スタック操作が減る
  • ○メソッドからの返り値(1変数)がレジスタ経由で行える

■スタック

  • ○スタックへの格納が1命令で行える
  • ○命令がシンプルになる
  • ○命令列がコンパクト

性能的には、スタックへ格納する率が多ければ後者が有利になるのかな。命令を分けたことによる性能差がどれくらいになるのかよくわからないが。

とにかくメソッド呼び出しを速くしなければならない ruby を考えてみると、レジスタのほうが有利、なのかな。


あぁ、すげー初歩的なところで悩んでいる気がする。

プロセッサ作るのなら、フラグによってスタックへ格納するかレジスタへ格納するか分けてもいいんだろうけどな。

Implementation of Stack-Based Languages on Register Machines 面白そうだな。しかし、これで卒論なのか・・・。


とりあえずレジスタにするように書き換えてみるか・・・。


今の ruby の C用 API を使おうとすると、拡張ライブラリのメソッドコールって全部クリティカルセクションにしないといけないのかな。うわ・・・。あれ、そんなことないのかな? うーん?

既存の C コードとの、例外のやり取りってどうやるんだ・・・。raise in C code はフックできるだろうが、rescue in C code って無理かな・・・。C の rescue の方法って知らないけど。push_xxx するのかしらん。


今日の古本。久しぶりに古本屋で散在。今月の読書会(の飲み会)は、マジでヤバイ。

また本棚の肥やしが増えた。


新・闘わないプログラマ No.298。すげー。確かに見てみたい。

nobsun さんの日記のコメント、長すぎ。


高性能プログラミング。あー、非常にわかりやすい。一覧が素晴らしい。


エイヤっと論文を整理(といってもファイルに押し込んだだけ)。いい加減にカテゴライズしたら、4つほどファイルが余った。

論文100個くらいあるんじゃなかろうか。もちろん、まじめに読んだ論文は10個にも満たない(マテ)。

先日見つけて「おー、すげーこの論文」とか思ってたのが、昔々に刷ってあったことを発見する。うーむむ・・・。

やっぱ、刷るだけ刷って、安心してしまうのはよくないな。なんとかならないものか。


いろいろやってたんだが、結局明日のゼミの資料は出来ていない。どうしたものか。

『イリヤの空、UFOの夏』特製ブックレット付きドラマCD。悩む。悩む。そんな金ないってば。でも、無銭飲食列伝はとてもとても聞いてみたい。聞いてみたい。うーん・・・。別にこつえー氏の絵に転んだってわけではなく。


ruby で「箱」(間接参照のための何か)を作るには、どれが一番効率がいいのか。とりあえず思いついたもので、クラスと配列とハッシュで確認。

require 'benchmark'
include Benchmark

obj = Object.new
class <<obj
  attr_accessor :ivar
end
obj.ivar = nil

ary = [nil]
hash = {:var=>nil}

LC = 1000000

bmbm{|bm|
  bm.report{
    LC.times{
      obj.ivar = 10
      a = obj.ivar
    }
  }
  bm.report{
    LC.times{
      ary[0] = 10
      a = ary[0]
    }
  }
  bm.report{
    LC.times{
      hash[:var] = 10
      a = hash[:var]
    }
  }
}

#=>
       user     system      total        real
   1.875000   0.000000   1.875000 (  1.875000) # obj
   1.781000   0.000000   1.781000 (  1.781000) # ary
   2.032000   0.000000   2.032000 (  2.047000) # hash

array が速くなったのか、hash が遅くなったのか。arry だろうな。

まぁ、array が一番速そう。


うわ、雨降ってる。帰れねぇ。

というわけで、ノートPCに入れていた Ever17 をやる。備えあれば憂いなし(違)。

_shiro(Mon Sep 15 11:50:24 JST 2003)

性能にはいろんな事情が絡んできますが、vmのループが最終的に機械語に落ちる場合は、vmのレジスタがCPUのレジスタに載ることが期待できる分だけ(レジスタ使用が)有利かなあ。(Gaucheでは、val0レジスタはvmループのローカル変数で、必要な場合だけScmVMRec->val0へと退避されます)。ただ、命令列をコンパクトにするのも結構性能に効いて来るので、その効果が期待できるなら全部スタックの方が良いかも。

_ささだ(Mon Sep 15 12:05:18 JST 2003)

 Gauche VM命令セットを決めたのは、shiroさんの勘が主ですか?

_sxxxo(Mon Sep 15 14:23:10 JST 2003)

 スタックマシンのVMにレジスタを持たせるような半端なこと(超失礼)しないで、JITコンパイルしようぜ! とか言ってみる

_shiro(Mon Sep 15 14:54:29 JST 2003)

勘という程のこともなく、何も工夫のない命令セットだと思います。 とりあえず動かすことが先決で、そのあとチューンすればいいと思っていたので。 実際に動かしてみながら若干調整したところはあります。 ちょっと変わっているところがあるとすれば、引数フレームより先に 継続フレームを積むため、PRE_CALL, PRE_TAILという命令があるところかな。 これも別に私のオリジナルではなく、「継続フレームを先に積んでおくとtail callが 簡略化されるよん」というのをどっかで読んだからです (R.Kelsey "Tail-Recursive Stack Disciplines for an Interpreter" だったかな)。 個人的な経験では、VM命令セットよりもスタックフレームのデザインが重要かと思います。

_ささだ(Mon Sep 15 15:42:52 JST 2003)

 いや、非常に納得いく仕様だと感じました(全て読んだわけではありませんが)。先にフレームを積むのは、Smalltalk でもやっているようでした。私も先にフレームを積むほうがいいんじゃ、とか思ってます。とか言う。

_kjana(Tue Sep 16 00:55:49 JST 2003)

コードが小さくなったところでどうせアクセスはワード単位だとか、 スタックマシンだと命令の並べ変えが面倒臭そうだとか、怪しげな 判断基準を持ち込んでみたり。

rvm だとか vvm だとか怪しく汎用 VM の実装を提示してみたり。

_ささだ(Tue Sep 16 06:48:31 JST 2003)

 コードが小さくなれば、命令フェッチ&デコードの手間が減るからいいんじゃないでしょうか。命令の並べ替えって、なんですか? JITコンパイル?

_kjana(Tue Sep 16 13:53:07 JST 2003)

fetch はデータがアクセスが word align だったりすると byte code に なってたとしてもあんまり嬉しくないかもしれないという話です.decode はあんまり考えてません.少ない方が表引きも速いのは確かでしょうけど, byte 単位でメモリアクセスするより word 単位のが.... ああ? packed byte array にできたらキャッシュにやさしくて速くなるのか? やっぱり適 当に考えてもまともな判断基準にならない....

命令が 256 個までに収まっててくれると 32bit register で 256 個のレ ジスタ三つ指定してちょうどとか,そうすると (operation, destination, source, target) みたいな四つ組がそのまま表現できるとかそんな感じと か.どのみち定数のオペランドがな.... R3000 みたいにジャンプの飛び先 に制限があったり,word いっぱいの整数を即値で扱えなかったりしそうだ.

命令の並べ替えってのは VM レベルでも最適化が効くかもしれないという話 で,実はわざわざ VM 命令レベルでやらんでもという気がしてたんで怪しい 話と :-P byte code を word 単位にパックして扱う VLIW や EPIC な VM は 楽しいかもしれないけど多分自己満足 :-)

_ささだ(Tue Sep 16 14:08:48 JST 2003)

 あー、1命令のサイズの小ささの話だったんですね。私はプログラムの命令列の短さを考えていました。私も個人的にはバイトコードなんてダメっぽいので、ワードコードにしようと考えいます。いまどき、そんなところでメモリけちる必要はないでしょうから。命令列に対するD cache miss ですが・・・。うーん、シーケンシャルな読み込みなんで、そんな影響ないような気がするけどなぁ。

 レジスタマシンのVMは・・・どうなんでしょうね。Parrot、結局どうなるのかな。

 VM命令レベルでの命令の並べ替えについては、並べ替えとはいえないかもしれないけどpeephole最適化による命令の置き換えは有効だそうです。VLIW なVMは考えたこともなかったけど、スーパースカラなVMは4年のときやろうとしてました :)。まだ野望は捨ててません。捨てたほうが賢明だろが。

_shiro(Tue Sep 16 16:46:00 JST 2003)

VMにとって何が最適かは、目的を絞らないと発散しますね。スクリプト言語では、コンパイルにそんなに時間をかけられないという事情があります。Hotspotだけ徐々に最適化してくのはありかもしれませんが。ネイティブコードに落とすなら最初からフルコンパイルしちゃえばいいような気もします(普通のCommonLispシステムはトップレベルで式をタイプするたびにネイティブにコンパイルしているけど、あれはJITとは言いませんよね)。

Gaucheについて言えば、現在は1命令1ワードのトークンディスパッチ方式で、定数は小さいものはVM命令のビットフィールドに押し込み、それ以外はそのまま命令列に含ませています。よく出てくる命令シーケンスについては、合成命令を作って命令数を減らすと性能向上に若干効果がありました。I cacheに載らなくなるくらいVMループが大きくなりさえしなければ、CISC的な命令セットにした方がよさげに思います。

最速インタプリタをうたうQschemeという処理系はthreaded codeを使っているので、一度Gaucheでも試してみたいと思っています。元祖Pentiumではデータとコードを混ぜると良くないというベンチがありましたが…

_14(Sun)

暑い! 暑すぎて目が覚めた。なんだこの気温は。


Ruby 使ってる?の結果を見ると、Rubyは知らない人が居ない、メジャーな言語ということがわかりました。つまり、そのへん歩いている人に聞いてみれば、みんな Ruby って知ってるってことですね。


プログラミング言語のユーザビリティ、というテーマから、マクロのユーザビリティ、という話になってきているようですが。

eval ってどうなんですかね。あれは cpp みたいなもん(凄い乱暴だ)だと思うんですが。いや、cpp は乱暴すぎるか。

ruby の attr_reader とかって、言語の機能っぽい(予約語っぽい)ですけど、そういうわけじゃないですよね。


暑いので学校に避難するか・・・。


コンパイルするようにすれば、使い物になるかなぁ。やってみようかなぁ。どうしよ。


やばい、MR の実行ログを表示したまま席を立ったら、妹が部屋に居た・・・。

_ahiru(Sun Sep 14 16:27:30 JST 2003)

 ご愁傷様です

_sk(Sun Sep 14 22:28:14 JST 2003)

 ^Dすると、妹が泣きだしますよ

_ささだ(Mon Sep 15 07:21:50 JST 2003)

 インタープリタ真面目に作ってなくて ^^;

_13(Sat)

東方妖々夢いいですよー

いくらよくても喫茶店でやるものでしょうか?(いや、デモだけど)


正規表現ってよく知らないんですが。

r1 = /(a)/
r2 = /(b)(c)/
r  = /(#{r1})(#{r2})/
r =~ 'abc'
p [$1,$2,$3,$4,$5]

#=> ["a", "a", "bc", "b", "c"]

r の $1,$2 は 'a' と 'bc' になって欲しかったけど、やっぱり無理か。やはり racc を使うか。

すべてのパターンを根性で並べるのは多分ダメだろうなぁ。


http://mtndbys.s14.xrea.com/seezle/seezle/diary/?date=20030912#p05

匿名で(臆病者)つっこもうと思ったけど長いのでこっちに書く。

proper な理由? 文脈からしていーかげんな理由ってことかしらん。

個人的にはどんな理由で行ってもいいのだけど、他の人の足をひっぱってくれるな、と思ったりする愚痴。

もちろん、やる気があるけれど足をひっぱってしまうのはしょうがない、それは教育者側の努力で底上げしてしかるべきなのだが、「別に俺これやりたいわけじゃないしー」とかいって努力もしない馬鹿のために教育のレベルを下げている現状は、やる気のある学生から見ると非常に不愉快(自分にはやる気があったか、という点については後述)。

別に勉強(教育を受ける)だけが大学じゃないから一つの側面でしかないんだけどさ。

それに甘んじてレベルの低い教育しか行わない大学もダメなんだが...。(これは、大学側にたってみれば、「しょーがねーだろ」といわれるかもしれないな。だからそっち側に回りたくないんだけど...)

レベルの低い教育⇒やる気がなくてもなんとなく卒業できる⇒やる気がない奴が集まる⇒(最初に戻る)

という悪循環。逆のスパイラルにするには英断が必要なんだろう。大学選びは大切だということを、今更になって思う。でも、高校生にはどの大学がどうだ、なんてわかんねーよなぁ。

やる気がある奴は自分で勝手にやる、そもそも大学なんて教えてもらいに行くもんじゃない、と言われると、まったくそのとおりなんだけど。だけど金払ってんだもん、得られるものは多いほうがいいじゃん。

え、俺っすか? 結局独学も何もしてなかったやる気のない学生だった。だから、今知らないことばかりでアップアップしてるわけだ。ヤレヤレ。4年になってから勉強しだしたようなもんだよ...。そもそもこんな人のせいにするような文を書いてる時点で甘えてるし。まぁ、甘えてしまうから、縛りというものがあるといいなぁと思うのだけど。現在は適度にしばり(修論)があって、適度に余裕(修論は来年度末提出)があって、とてもいい感じだけど。

そういう点でK本さんは凄いよな。自分でどんどんいろんなことやってんだもん。いや、ほんと尊敬してます。多分。ということで今月の飲み会、もとい読書会はおごって下さい。温泉行くので今月ピンチなんです。


教育といえば、電通大ではプロトコルスタック2人、コンパイラ2人、CPU2人の6人チームでそれぞれの仕事を半年でするって実習があるらしいと聞いた。いいなぁ、こういう実習。とても楽しそうだ。

東大のCPU・コンパイラ製作実習をリファーするようなものらしいけれど。まぁ、大学側は非常に大変そうだが・・・。

いや、農工大にもシステム製作実験っていう、2 or 3人でなんか作れっていう話もあるんですけどね。まぁ、これはこれで、自由度が高くて楽しかったなぁ。研究の方法とか何もわからず、とにかくやるだけに終わっていたが。もうちょっと色々知っていれば、もうちょっといろんなことが出来たと思うんだけど。1年から毎年これやってくれれば楽しかったんだろうになぁ。

やっぱり色々と選べるようにするべきだよな。一律同じカリキュラムってのは、やっぱりおかしい。なんで今更 is_alpha とかを再実装せにゃならん。しかも比較使って(と、is_alpha を使って実験レポートを書いたら×をつけられたことを未だに根に持っている)。


えーと、あまりに自分勝手な意見なので、上記は無視してください。

でも、飲み会はおごって下さい>岸Mさん


Rucheme による置き換えモデルの表示。

<== (define (inc a) (+ a 1))
==> 
<== (define (dec a) (- a 1))
==> 
<== (define (+A a b) (if (= a 0) b (inc (+A (dec a) b))))
==> 
<== (define (+B a b) (if (= a 0) b (+B (dec a) (inc b))))
==> 
<== (+A 5 7)
(+A 5 7)
(if (= 5 0) b (inc (+A (dec a) b)))
(if #f b (inc (+A (dec a) b)))
(inc (+A (dec 5) b))
(inc (+A (- 5 1) b))
(inc (+A 4 7))
(inc (if (= 4 0) b (inc (+A (dec a) b))))
(inc (if #f b (inc (+A (dec a) b))))
(inc (inc (+A (dec 4) b)))
(inc (inc (+A (- 4 1) b)))
(inc (inc (+A 3 7)))
(inc (inc (if (= 3 0) b (inc (+A (dec a) b)))))
(inc (inc (if #f b (inc (+A (dec a) b)))))
(inc (inc (inc (+A (dec 3) b))))
(inc (inc (inc (+A (- 3 1) b))))
(inc (inc (inc (+A 2 7))))
(inc (inc (inc (if (= 2 0) b (inc (+A (dec a) b))))))
(inc (inc (inc (if #f b (inc (+A (dec a) b))))))
(inc (inc (inc (inc (+A (dec 2) b)))))
(inc (inc (inc (inc (+A (- 2 1) b)))))
(inc (inc (inc (inc (+A 1 7)))))
(inc (inc (inc (inc (if (= 1 0) b (inc (+A (dec a) b)))))))
(inc (inc (inc (inc (if #f b (inc (+A (dec a) b)))))))
(inc (inc (inc (inc (inc (+A (dec 1) b))))))
(inc (inc (inc (inc (inc (+A (- 1 1) b))))))
(inc (inc (inc (inc (inc (+A 0 7))))))
(inc (inc (inc (inc (inc (if (= 0 0) b (inc (+A (dec a) b))))))))
(inc (inc (inc (inc (inc (if #t b (inc (+A (dec a) b))))))))
(inc (inc (inc (inc (inc 7)))))
(inc (inc (inc (inc (+ 7 1)))))
(inc (inc (inc (inc 8))))
(inc (inc (inc (+ 8 1))))
(inc (inc (inc 9)))
(inc (inc (+ 9 1)))
(inc (inc 10))
(inc (+ 10 1))
(inc 11)
(+ 11 1)
==> 12
<== (+B 5 7)
(+B 5 7)
(if (= 5 0) b (+B (dec a) (inc b)))
(if #f b (+B (dec a) (inc b)))
(+B (dec 5) (inc b))
(+B (- 5 1) (inc b))
(+B 4 (inc 7))
(+B 4 (+ 7 1))
(+B 4 8)
(if (= 4 0) b (+B (dec a) (inc b)))
(if #f b (+B (dec a) (inc b)))
(+B (dec 4) (inc b))
(+B (- 4 1) (inc b))
(+B 3 (inc 8))
(+B 3 (+ 8 1))
(+B 3 9)
(if (= 3 0) b (+B (dec a) (inc b)))
(if #f b (+B (dec a) (inc b)))
(+B (dec 3) (inc b))
(+B (- 3 1) (inc b))
(+B 2 (inc 9))
(+B 2 (+ 9 1))
(+B 2 10)
(if (= 2 0) b (+B (dec a) (inc b)))
(if #f b (+B (dec a) (inc b)))
(+B (dec 2) (inc b))
(+B (- 2 1) (inc b))
(+B 1 (inc 10))
(+B 1 (+ 10 1))
(+B 1 11)
(if (= 1 0) b (+B (dec a) (inc b)))
(if #f b (+B (dec a) (inc b)))
(+B (dec 1) (inc b))
(+B (- 1 1) (inc b))
(+B 0 (inc 11))
(+B 0 (+ 11 1))
(+B 0 12)
(if (= 0 0) b (+B (dec a) (inc b)))
(if #t b (+B (dec a) (inc b)))
==> 12

これ、教育用に使えないかなぁ。使えないかぁ。


レキシカルスコープの場合、静的にバインディングの位置が決まるので、ギチギチにコンパイルするときはとくに何も工夫は要らない。○か×か。


インタープリタを作っていて、定数の再定義が便利であることを悟る。うーむ。

_mput@電通大です(Sat Sep 13 09:15:39 JST 2003)

 いいなぁ、それやりたかったなぁ。どこの学科なんだろう。

_ささだ(Sat Sep 13 10:14:53 JST 2003)

 この話は昨日、鈴木(貢)さんに聞きました。

_おだか(普段は話についていけてないB4)(Sat Sep 13 22:00:27 JST 2003)

自分はサークルやってて授業はいい加減だった人間ですが、 読んでて納得して自分が反省すべき部分もある気もするけど、 やっぱり納得いかない部分もあるような気がします。うーむ。

_shudo(Sat Sep 13 22:51:31 JST 2003)

 早稲田 情報学科では、12 bitプロセッサ作ったよ。教科書通りのものを CAD ソフトに入力すれば出来るんだけど、自分達でイジる余地があって、ココとアソコは同時に動かせるなあ、とか考えてシーケンサをイジるのが楽しかった覚えがある。教科書はこれ http://www.saiensu.co.jp/books-htm/ISBN4-7819-0765-2.htm

_12(Fri)

CPS じゃないよなぁ、これ。やっぱり。continuation を適用するとき、フレームコピーしてちゃ・・・。とりあえず正しく動くけど、なんか違う。

一度 continuation 作ったら、そいつに対して破壊的な何かをしちゃいけないんだな。で、そうするためにはリストにしないと・・・。


処理速度測定のため、新しいのにS式つっこんでみてたら。なーんか処理がおわんねーなーってドキドキしてたら、ファイルを指定してなくて、標準入力からの待ちになってた。

あれ、なんか速くなったな。proc から __send__ にしたからか。

ついでに、continuation を marshal してみる。環境までくっつけちゃうのは、ちょっとまずいかもしれないな。まぁ、これでマイグレーションも出来るでしょう。多分。


しまった、トップレベルの環境とそれ以外の環境ってわけないと駄目なのか。あれ、そんなことないか?

マイグレーションしたとき、トップレベルの環境をどうするのかって結構問題だな。現状だと元のを全部持っていくことになって、移動先のトップレベルを無視することになる。

まぁ、それでもいいような気がするが。

インタプリタの中断が出来るか、これで。


うーん、なんか速くなってるぞ。なんでだろう。よくわからない。


こいつで CGI を動かすことを考えてみる。セッションごとにコンティニュエーションを作って、、、うーん、どうなんだろうな。


ということで、rucheme 0.2.0 です。もうバージョンアップかよって感じですが、前がダメダメだったんで。で、結構よくなったと自負してます。

to-yaml って関数つけたんですが、結構面白いかもしれない。

ちなみに ML は全然余裕があります。多分。


business navi 特集 『こうは絶対なりたくない! 飲み会のウザいヤツ大特集』(mput's essay)。

盛り上がっている最中に帰ってしまう

それはしょうがないんじゃ・・・。じゃぁどうしろっつうんだろ。


vm.c:VMインタプリタ(メインループ)。大変興味深いのです。


11時。学校に帰室。

神田駅には初めて降りた。地図を忘れて無茶苦茶迷う。三菱総研に行くはずが、三菱マテリアルで道を聞く。全然違うところ歩いてるじゃーん。遅刻。階段で行ったら締め切られていた。受付のお姉さんは冷たかった。ケーキのでる会議室は初めてだった。

甘いものを奢っていただきました。ありがとうございました。あれだけ濃い最適化の話を聞いたのは初めてでした。まさか東方妖々夢のデモを見るとは思わなかったですが。


ストライクゾーンチェッカー

あなたの本来のストライクゾーンは17〜26歳です。

本来って言われてもな。

_K本(Fri Sep 12 09:37:56 JST 2003)

 私に cannibalism の趣味はありませんが... stdin とかは移動先のほうにリダイレクトしたいか元のほうで動いてほしいか,微妙ですよね.HORB を使っていて,JVM ごとに挙動が違うコードに,はまったことがあります.

_ささだ(Fri Sep 12 09:42:07 JST 2003)

 いや、その環境じゃなくて、バインディングする環境

_み(Fri Sep 12 10:14:39 JST 2003)

 論文別刷り届いたよ。記念贈呈するから、来たときね。

_ささだ(Fri Sep 12 10:28:09 JST 2003)

 どうもです。

_さかい(Sat Sep 13 01:09:38 JST 2003)

 東方妖々夢いいですよー

_11(Thu)

require 'benchmark'
include Benchmark

class Pair
  def initialize a,b
    @car = a; @cdr = b
  end
  attr_reader :car,:cdr
end


def m1 a,b
  a + b
end

def m2 a
  a[0] + a[1]
end

def m3 arg
  a = arg.car; arg = arg.cdr
  b = arg.car; 

  a + b
end

def m4 arg
  a = arg[0]; arg = arg[1]
  b = arg[0];

  a + b
end


ary = [0,1]
par = Pair.new(0,Pair.new(1,0))

LC = 50000000

bm{|b|
  b.report{
    LC.times{
      m1(0,1)
    }
  }
  b.report{
    LC.times{
      a = []
      a << 0
      a << 1
      m1(*a)
    }
  }
  b.report{
    LC.times{
      a = []
      a << 0
      a << 1
      m2(a)
    }
  }
  b.report{
    LC.times{
      p = Pair.new(0,0)
      p = Pair.new(0,p)
      m3(p)
    }
  }
  b.report{
    LC.times{
      p = [1,0]
      p = [0,p]
      m4(p)
    }
  }
}

#=>
      user     system      total        real
 86.094000   0.000000  86.094000 ( 86.657000)
258.672000   7.594000 266.266000 (269.984000)
312.938000   9.141000 322.079000 (326.266000)
1200.359000  37.921000 1238.280000 (1258.453000)
365.312000   2.750000 368.062000 (373.172000)

うー、12倍・・・。うー・・・。

これは、Pair を C で書けば、速くなるかな。。。なら、Pair で行くか。


笑った。 from f2c.h

/**  barf  [ba:rf]  2.  "He suggested using FORTRAN, and everybody barfed."

	- From The Shogakukan DICTIONARY OF NEW ENGLISH (Second edition) */

あー、帰りたい。せめて夕飯が食べたい。


そういえば、和歌山行ったとき、第六大陸という本を読みました。K本さんに強く勧められたからなんですが。

内容は、13歳の少女にいろいろと恥ずかしい行為をさせて、最後は食べてしまう、という感じ。さすが岸Mさんが勧める小説です。

プロジェクトXって感じなんですかね。1500億は安すぎるんじゃないかなぁ・・・。


バグがあるのはわかってんだが、それをなおす気力が出ない。むー。徹夜はやっぱりいかんな。


テーブルを wikiスタイルにどう組み込むか。んー。


わー、WEBrich ってこうやって使うんだー・・・。スゲー。

というわけで、何か出来ないかなー、とやってみようとしたけれど、何をどうしていいのかわからなかったので挫折。偉い人はどうやって使ってるんだろう。

shutdown に時間がかかる。windowsだからなのかな。何か入力すると、DOS窓に反応が無くなる。どうやって待ってるんだろう。select 関連で、なんかアレなのかな・・・。


include WEBrick

s = HTTPServer.new( :Port => 2000 )

class ClassesViewerServlet < HTTPServlet::AbstractServlet
  def do_GET(req, res)
    res.body = "<HTML><pre>#{class_list}</pre></HTML>"
    res['Content-Type'] = "text/html"
  end
  def class_list
    lst = []
    ObjectSpace.each_object{|obj|
      if obj.kind_of? Class
        lst << "<a href='class/#{obj.to_s}'>#{obj.to_s}</a>"
      end
    }
    lst.sort.join("\n")
  end
end

class ClassViewerServlet < HTTPServlet::AbstractServlet
  def do_GET(req, res)
    res.body = "<HTML><pre>#{method_list(req.path)}</pre></HTML>"
    res['Content-Type'] = "text/html"
  end

  def method_list klass
    /\/class\/(.+)/ =~ klass.to_s
    classname = $1
    klass = eval($1)
    klass.instance_methods.sort.map{|e|
      "<a href='./method/#{classname}.#{e}'>#{e}</a>"
    }.join("\n")
  end
end

class MethodViewerServlet < HTTPServlet::AbstractServlet
  def do_GET(req, res)
    res.body = "<html><p>#{referu(req.path_info)}</p></html>"
    res['Content-Type'] = "text/html"
  end

  def referu n
    /\/(.+)/ =~ n
    $1 + "\n" + `refe.bat #{$1}`.to_s
  end
end

s.mount("/class/method", MethodViewerServlet)
s.mount("/class", ClassViewerServlet)
s.mount("/", ClassesViewerServlet)

trap("INT"){ s.shutdown }
s.start

えらいいい加減。


今日の失敗(の一つ)。定数のつもりで __NANTOKA__ と書いていてエラー。やられた。


やむる(YAML)があるんだかられふぇるがあってもいいんぢゃないだろうか。(よくない)

require 'refe/database'

class Object
  REFERU_DB__ = ReFe::Database.new.method_document

  def referu key
    key = "#{self.class}##{key}"
    begin
      REFERU_DB__[key]
    rescue
      'no reference'
    end
  end
end

puts "str".referu(:sub)
_KM(Thu Sep 11 09:46:08 JST 2003)

 昨日買って読んだのだが,朝日選書「霊柩車の誕生」は面白いぞ(って,めいど違いでつね)

_kjana(Thu Sep 11 18:57:32 JST 2003)

 typo に微妙に願望が反映されてますね :-) >> WEBrich

_ささだ(Thu Sep 11 19:55:27 JST 2003)

 WEBrich でウハウハ生活。

_10(Wed)

出来るところでは == を equal? に変更。kind_of? を respond_to? に変更。Symbol にはわざわざ symbol? というメソッドを追加してしまった。

焼け石に水という噂もある。

配列の、最初の要素とそれ以降、まぁリストにおける car と cdr に分けたい処理があったんだけど、ary[1..-1] ではコピーが起きて嫌だな、ということで、わざわざクラスを一個用意して管理することにする。

遅くなってしまった・・・。コピー起きないのかな、もしかして。うーん、起きないか。元に戻すかなぁ。。。見た目的にはクラスで管理したほうが綺麗なんだけど。

戻したら 15% 早くなった。ヤレヤレ。


call/cc もやったし、もうこれくらいでいいか。しかし、速度比 1000倍ってのもなんだかなぁ。

(define (count x y)
        (if (= x 0)
            y
          (count (- x 1) (+ y 1))))
(count 100000 0)

具体的には上記コードが 2分弱(500Mhz ノート)。Gauche だと一瞬。

とりあえずリリースしよう。前回の RHG 読書会の議論の成果なわけですので、是非見てもらいたいとは思っているわけです。


wiki で S式を使うってのが流行っているようなので、hiki にでも入れてみようか。でも、私は hiki をよく知らない。

ちなみに、continuation の migration は、今はまだできない。永続化も同様。どうしようかな、できるようにするべきか・・・。少し弄れば出来そうだけど。continuation を yaml で、とか。うへ。


しかし、スタックオーバーフローが起きなくなったのはいいが、逆にその制限ができなくなってしまった。ちょっと大きな再帰構造をかけるとメモリ食いまくり。CPU占有率が0って何事じゃー、とか思ったんだけど、スワップに時間が食われまくりらしく。

スタックサイズを数えるのはちょっと負荷が気になるんだけど。どうしたもんかな。でも、ソフトウェア組み込みで利用するにはそれがないと駄目かな・・・。

やっぱり、評価器自体を再帰呼び出し、のほうがスクリプト言語では良いのかもしれないなぁ。


私は凄い厳密な処理系を作ってるけど、そうじゃない処理系のほうが実用性は高いのかな。たとえば、if などの式はバインディング不可、とか。誰も if なんて束縛しないよね。そうしてしまえば、相当早くなるんだけど。パース時点でやること決めてみたり。


そういえば、恥ずかしながらやっと lexical closure についてわかったような気がする。あぁ、lexical だぁ、と。遅。


google オメー。


こんなものは嫌だシリーズ。喋らない番兵君。

o = Foo.new
begin
  p o.__id__
rescue
  p "dumb sentinel!."
end

というわけで Rucheme ふたたび、なのです。対話型インタプリタの開発には是非大人数で望みたいのだけど、MLには何人くるか。

テーマなんだけど、ネットワーク対応テーマを考えています。そこまでやって誰が使うんだ、という気がとてもとてもするんだけど。


いや、別に10人で制限ってつもりじゃなくて、10人も居ないだろう、って判断なんですが・・・。無理そうならほかに移します。でも、10人来ないだろう、きっと。


test/unit とか、rubyunit とか、テストツールってどうやって使い分けるものなのでしょうか。


OpenMP。大変わかりやすい解説。広い並列性へのディレクティブだけど、最初の動機はやっぱり SMP みたいですよ。


正規表現、前置記法にするのなら、 (=~ #/abc/ "abc") みたいになるのかな。何を返すんだろう。MatchData 返せばいいんかな。


0.1.1 ということで、named let に対応。より具体的にはさかえさんのところの 引数の数 に対応。

あと、let にバグがあったので修正。新しい環境つかってねーでやんの。


Catan 公式サイト。カタンネットゲームになるのね。俺、一度も勝ったことが無いんだよな。やっぱりこれは頭のよしあしなんだろうなぁ。


せっかく遅いのにも関わらずまじめに評価してるんだから、もっとアグレッシブな機能が付けられるかも知れない。たとえば、実行中に Ctrl+C で止めて、トップ環境を変更してまた再開するとか。一部をロールバックする機構さえ作れば出来ないことはない、のかな。ほんとか? 今度やってみよう。


今番兵君に Object.new を使ってるんだけど、marshal したときにダメダメになるね・・・。どうしようかな。

Pair だけ dump_ とか加工しようかしら。


あぁ、バグ発見。ううん・・・。これは根本的解決は・・・それこそまじめに CPS するか。

うわ、大改造が必要。

とすると、push_frame / pop_frame という名前を変えたほうがいいんだろうな。Continuation.new に restore_continuation 、になるのかな・・・。それこそ call_continuation にしてしまおうか。そのまんまだしな。

やっと CPS とは、ってわかってきたような気がする。でも、やっぱりよくわからない・・・。


ああ、ダメダメだ。実行時スタックのスナップショット、全然取ってない。あー・・・。別にスナップショットを取る必要はないか・・・。

うーん・・・。linked list と Array ・・・。配列 A の要素 n 個未満、というものを一つのオブジェクトとして扱う方法は無いものか・・・。やっぱりlinked list が必要に・・・。でも、__send__ にさくっと送れないしな・・・。


性能がー、っていろいろベンチマークとってたけど、そもそもこんなんなんだから、性能なんてどうでもいいかー。とりあえずキッチリ動くもの作るかー。

_ahiru(Wed Sep 10 02:11:04 JST 2003)

 い○○とモードはつけるのですか>Rucheme2(?)

_ささだ(Wed Sep 10 02:18:45 JST 2003)

 それが目玉です。

_babie(Wed Sep 10 19:14:23 JST 2003)

 Ruchemeメーリングリスト入りたいんですが、RubyもSchemeもヘナチョコなので、当座はROMしかできないと思います。パイが少ないので躊躇しています。公開アーカイブが出来ればうれしいです。

_ささだ(Wed Sep 10 19:32:40 JST 2003)

 私もへなちょこなので多分大丈夫です。へなちょこなので、公開アーカイブを作る気力がありません。ちなみに今2人ほどいらっしゃるようです。やっぱり2人、ニッチな話です。

_ささだ(Wed Sep 10 19:34:21 JST 2003)

 というか、私が教えて君モードになるためのMLなので(ぇ)、人数は多いほうがいいんじゃないか、とか。というか、猫耳とかメイドとか、詳しい人きてくれないかなぁ。

_n???n(Wed Sep 10 20:37:18 JST 2003)

 QuickML なんだから直接召喚すへし。xxxx さんとか ooo さんとか。。。

_ささだ(Wed Sep 10 20:39:53 JST 2003)

 メイドと Scheme 双方に通じてる人って知らないのですよねぇ。誰が知りません?

_ahiru(Wed Sep 10 20:47:15 JST 2003)

 Schemeに通じている人をメイド色に染める、って方法も。

_9(Tue)

apply の3個目以降の引数ってどういうシチュエーションで使うんだろう・・・。

うー、ソースが汚い・・・。apply, map, for-each 終り。汚いなぁ・・・。

んー、named let 出来るようにするべきか・・・。面倒くさいな・・・。


    # (let <bindings> <body>) 
    self.def_syntax 'let', %q{
      bindings = args.car
      body = args.cdr
      env  = Environment.new @env
      var  = nil
      
      pr = lambda{|result|
        env.define var, result if var
        
        if bindings == Nil
          begin_sexp body, env
        else
          var  = bindings.car.car
          init = bindings.car.cdr.car
          bindings = bindings.cdr
          
          #p var.to_s
          #p init.to_s

          push_frame init, @env, pr         <==== ココ
        end
      }
      pr.call(nil)
    }

    # (let* <bindings> <body>) 
    self.def_syntax 'let*', %q{
      bindings = args.car
      body = args.cdr
      env  = Environment.new @env
      var  = nil
      
      pr = lambda{|result|
        env.define var, result if var
        
        if bindings == Nil
          begin_sexp body, env
        else
          var  = bindings.car.car
          init = bindings.car.cdr.car
          bindings = bindings.cdr
          
          #p var.to_s
          #p init.to_s

          push_frame init, env, pr          <==== ココ
        end
      }
      pr.call(nil)
    }

let と let*。非常に嫌な感じがします。たった一文字違うだけのコピペ。どうまとめるのが綺麗か。はて。

    def syn_let args, env, passing_env
      bindings = args.car
      body = args.cdr
      var  = nil
      
      pr = lambda{|result|
        env.define var, result if var
        
        if bindings == Nil
          begin_sexp body, env
        else
          var  = bindings.car.car
          init = bindings.car.cdr.car
          bindings = bindings.cdr
          
          #p var.to_s
          #p init.to_s

          push_frame init, passing_env, pr
        end
      }
      pr.call(nil)
    end
    
    # (let <bindings> <body>) 
    self.def_syntax 'let', %q{
      env  = Environment.new @env
      syn_let args, env, @env
    }

    # (let* <bindings> <body>) 
    self.def_syntax 'let*', %q{
      env  = Environment.new @env
      syn_let args, env, env
    }

とりあえずこんな感じ。

こんな感じのぐちゃぐちゃのコードで動いてるのは自分でも驚き。

あ、この定義 letrec か・・・。

    def syn_let args
      bindings = args.car
      body     = args.cdr
      var      = nil
      
      passing_env = Environment.new @env
      
      pr = lambda{|result|
        passing_env.define var, result if var
        
        if bindings == Nil
          begin_sexp body, passing_env
        else
          var  = bindings.car.car
          init = bindings.car.cdr.car
          bindings = bindings.cdr
          
          #p var.to_s
          #p init.to_s
          passing_env = yield(passing_env)
          push_frame init, passing_env, pr
        end
      }
      pr.call(nil)
    end
    
    # (let <bindings> <body>) 
    self.def_syntax 'let', %q{
      syn_let(args){|e| @env}
    }

    # (let* <bindings> <body>) 
    self.def_syntax 'let*', %q{
      syn_let(args){|e| Environment.new e}
    }

    # (letrec <bindings> <body>) 
    self.def_syntax 'letrec', %q{
      syn_let(args){|e| e}
    }

なんか汚い・・・。


やっぱり、関数定義などを do/end じゃなくて {/} で出来るのは嬉しかったり。

うーん、マクロやっぱり面倒くさいな・・・。展開のタイミングもやっぱりよくわからないし。


Klass === obj と obj.kind_of? Klass 、どっちが速いか、のテスト(ruby1.8.0 mswin)

require 'benchmark'
include Benchmark
LC = 10000000
str = 'hoe'

bm{|bm|
  bm.report{
    LC.times{
      String === str
    }
  }
  bm.report{
    LC.times{
      str.kind_of? String
    }
  }
}
str = 103
bm{|bm|
  bm.report{
    LC.times{
      String === str
    }
  }
  bm.report{
    LC.times{
      str.kind_of? String
    }
  }
}

=begin
      user     system      total        real
 24.725000   0.000000  24.725000 ( 24.725000)
 24.465000   0.000000  24.465000 ( 24.495000)
      user     system      total        real
 27.039000   0.000000  27.039000 ( 27.039000)
 26.158000   0.000000  26.158000 ( 26.158000)
=end

kind_of? のほうが速いらしい。全部書き換えよう・・・。

しかし、false なときは遅いんだな。respond_to? でやったほうがいいのかもしれんなぁ。

  bm.report{
    LC.times{
      str.respond_to? :gsub
    }
  }
 を追加。

      user     system      total        real
 24.695000   0.000000  24.695000 ( 24.705000)
 24.465000   0.000000  24.465000 ( 24.505000)
 24.596000   0.000000  24.596000 ( 24.596000) # respond_to?
      user     system      total        real
 26.668000   0.000000  26.668000 ( 26.668000)
 26.138000   0.000000  26.138000 ( 26.138000)
 24.144000   0.000000  24.144000 ( 24.145000) # respond_to?

失敗時、クラスをたどらないから速い、と。respond_to? で全部書き換えるか。

_8(Mon)

QuickML.COM: 利用状況 を見る。凄いなぁ。右肩上がり。

というか、ちょこっと使わせてもらおうと思っていた矢先なので、ちょっと残念。どうしようかな。10人なら十分か。駄目そうだったら FreeML に移そう。


JDCセミナー:ガベージコレクション in Java ウワーーー、申し込みオワッテルーーー。しまった、やられた・・・。油断してた。

行こうか迷ってたけど、行けないとわかると行きたくてたまらなくなる。うーん。残念。


なんか流行ってるらしいあずまんが占い。「あなたは【美浜ちよ】なタイプ。」うーん、特に狙ったわけじゃないのになぁ・・・。ここで晒すと「やっぱり」とかいわれそうなきがするが、はて。

なんか、ノーベル賞取るらしい。計算機じゃとれねーよ。


先日のアレを新しいのでやってみたら、

(time (count l))
(time (count/cps l (lambda (x) x)))
(time (count/tr l 0))
(time (count/tr l 0))
(time (count/cps l (lambda (x) x)))
(time (count l))

time : 35.812   normal
100000
time : 101.672  cps
100000
time : 36.375   tr
100000
time : 35.859   tr
100000
time : 68.813   cps
100000
time : 39.453   normal
100000

GC だね、ボトルネックは。コリャ。やっぱ1フレーム1オブジェクトは贅沢すぎたかしらん。

_ahiru(Tue Sep 09 18:26:28 JST 2003)

 やっぱり?とうぜん?

_nobsun(Tue Sep 09 21:44:16 JST 2003)

 Turing 賞(

_6(Wed Sep 10 00:33:45 JST 2003)

 イグノーベル賞(ry

_7(Sun)

どうやっても再帰無しの評価器が作れない。というか、美しくない。細かい部分で駄目駄目。バイトコードにしてしまったほうが早いような気がしてきたぞ。


日本で最初の年号は「大化」。知ってた?。知らない人、結構居たっぽい?


syntax の評価ルールが未だによくわからないな。

(display and) は許されるのか、とか。(OK:G, NG:D,C)

うーん、なんか解決方法が思いついた気がする。しかし、R5RS 読んでも、正確なものってわからないな。数値の文字列表現とか、どこに載ってるんだろう。3####.#### ってなんだよ。精度関係なんだろうけど。3@4 とかも、書いてない気が。

結局3..4 がシンボルになれるのかっていうのも書いてないし。

あれ、 define って式キーワードじゃないの。そもそもシンタックスキーワードと式キーワードってどう違うんだ。値を持つか持たないかってことかな。


うわー・・・。末尾再帰版のほうが2倍遅い・・・。これはマズイ。何故だ。

うーん、関数フレームを作るとき、一個オブジェクトを作るのが敗因か。

あれ、作るオブジェクトの回数は同じか・・・。じゃぁGCかなぁ。

あ、文字列出力の問題だったらしい。S式の出力に時間がかかりすぎていたようで。出力部分だけ削っていたので、文字列生成部分のオーバーヘッドを見逃していた。

これで、末尾再帰、再帰無しと同等の速度になった。大体 Gauche の2倍くらいの遅さ。

やっと、旧 Rucheme に追いついたのかなー、これで。

_shiro(Sun Sep 07 19:00:58 JST 2003)

 R5RSは最低共通項を定めていて、意図的に処理系の解釈による拡張を許している部分があります。"3..4"に関しては、エラーにするかシンボルにするかでしょうが、わりと多くの処理系が、「数値として解釈できないトークンはシンボルとみなす」という方策を取っているようです。ちなみに3@4は7.1.1のプロダクションルールから導けますよ。 それから、syntactic keywordを評価した場合の動作は未定義なので、それも処理系依存ですね。

_ささだ(Sun Sep 07 19:12:12 JST 2003)

 なるほど。全仕様ってわけではない、ということですね。a@b が Complex であることは書いてあると思うのですが、これが極形式での表記というのは、実際に処理系で試すまでわかりませんでした。特に規定されてないのかなぁ。

 シンボルについてですが、気になっているのが、7.1.1 の識別子の定義が 識別子 ::= <頭文字> <後続文字>* となっていることで、頭文字には数字が入っていません。7.1.2 には、シンボル ::= 識別子 とも書いてあるようで。でも、試した処理系では、全て 3..4 をシンボル(及び識別子)にしてますね。

_ささだ(Sun Sep 07 19:44:35 JST 2003)

 そういえば、ライブラリ関係、何も書いてないですしねぇ。use とか。

_shiro(Sun Sep 07 21:26:32 JST 2003)

おお、本当だ。@の意味が書いてない>r5rs。今まで気づきませんでした。

7.1.1.の識別子の定義は、「r5rs準拠の処理系は最低限これは識別子として認識してね」というふうに読むべきもののようです。

_ささだ(Sun Sep 07 22:03:32 JST 2003)

 なるほど、最低限って意味がやっとわかりました ^^;

_新潟のS(Sun Sep 07 22:06:05 JST 2003)

 @が極形式というのは知りませんでした。ささださんのHPを見てると発見があるなぁ。

_6(Sat)

日が変わって帰宅。海が綺麗でした。遠くで見ただけだけど。


以前から困っていた「ノートPCについて、アダプターを刺しても充電されたりされなかったり」現象、やっと原因がわかった。アダプターのケーブルが断線してるのしてた・・・。ヤバスギル。火花散ってるし・・・。

これのためにいったいどれだけ苦労したことか・・・。


自己紹介を考えなければならない、というのは結構辛い。

本当のことを書くと、クライアントに不安を与えてしまう。というか、断られてしまう。こんな初心者を、ってな感じで。なので、適当に取捨選択しながらはったりをかます必要がある。でもあまりに大きいと、過剰な期待をもたれてしまう。

書いてみたら、はったりが効き過ぎてしまったような気がした。反省。

_4(Thu)

うーん、123c5 ってシンボルにしちゃっていいのかなぁ・・・。

う、数値ってきちんと parser 作んないと駄目かな・・・。RACC の練習してみるか。


win だと微妙にインストールがアレだったので、展開したアーカイブの中でテストしてみる。

簡単なのを書いてみる。ここまでわかるのが大変だった。ダメスギ。

sdigit10:
    flag DIGITS { result = val[0] * val[1] }
  | DIGITS      { result = val[0] }
  
flag :
    PLUS
    { result = 1 }
  | MINUS
    { result = -1 }

パース失敗のとき、それを伝えるには例外しかないだろうか。うーん。


数字の仕様、これ大変だなぁ・・・。

真面目に実装すると、スゲー長いような・・・。

やってみたら 8 shift/reduce conflict。仕様書どおりに行くなんて思うのが間違いか。

もうちょっと考えてみよう。256本読んで、RACC の勉強しないと。


というわけで、和歌山行ってきます。新幹線のお供は RHG。

_3(Wed)

暑い。


明日は4時半に家を出ないと間に合いません。多分。

というわけで、4時には起きないと間に合いません。多分。

寝坊しないためには、やっぱり徹夜しかないかな・・・。

まぁそういうわけで、2日くらい更新しません。多分。


妹テーマというのはわからないでもないが(わかるのかよ)、妹スケルトンって、なんか怖いな。

分散妹処理って、何処理するんですか。


あるソフトウェアに、A.rb と B.rb というファイルがあって、それぞれライブラリだとする。

A.rb のデバッグには、B.rb が必要、B.rb も A.rb が必要。if $0 == __FILE__ で、それぞれを require したんだけど、この場合、A.rb の起動と、require B で A.rb を二度読み込むことになるんだね。ヤラレタ。

テストコードはやっぱり別ファイルにしないといけないのか・・・。


素朴な疑問なんですが、Scheme って null list を作るのを '() って書くのが多いと思うんですが、() じゃだめなんでしょうか。私は後者で書いちゃうんだけど。


やっぱりテストがよくわかんないな。どういうファイル構成とかにすればいいんだろう。

はて、RSR5 には複素数表現についての規定がないのか? というか、リテラルについての定義か。どういう正規表現になるんだろうな。って、あった。7章か。しかし、これ全部サポートすんの辛いな・・・。

あれ。これか。R進数ってのが嫌だなぁ・・・。う、正規表現じゃ無理かも・・・。そんなことないか。


文字列の正規表現って (.*?((?!\\\\)|[^\\])) でいいのかなぁ。長いなぁ。格好悪いなぁ。

_mput(Wed Sep 03 22:33:05 JST 2003)

 if __FILE__ == $PROGRAM_NAME then $LOADED_FEATURES << __FILE__ end とか。

_ささだ(Wed Sep 03 23:14:59 JST 2003)

 English.rbって使ったことがなかったんで、なんのことか最初わからなかった ^^; $0 だとフルパス入っちゃって、面倒なのでやっぱり別ファイルにすることで解決しました。しかし、テストってめんどうくせー。

_shiro(Wed Sep 03 23:55:02 JST 2003)

 r5rsでは () は自己評価フォームではなかった覚えが。したがってホントは '() と書かないとだめ。

_ささだ(Thu Sep 04 00:07:18 JST 2003)

 あー、なるほど。リテラルに入ってないですね(リテラルは真偽値、数値、文字、文字列)。これから気をつけます。

_2(Tue)

%S{ } でS式評価してみたり?


gosh では

(let* ((a (cons 1 2)))
  (set-cdr! a a) a)

は無限ループするらしい。

Dr.Scheme は #0=(1 . #0#)

うーん、ちゃんと read 出来る。凄い。これを実現するには、最初にサイクルを探しておく、とかが必要なのかな。その後いっせいに処理。

仕様にこんなこと書いてあったかなぁ。


テストをしたことがないと言ったら「それはソフトウェアを作ったことにならない」(誇張)と言われたので、require 'test/unit' をと書いてみる。

うーん、やっぱりよくわからないので、誰かテスト書いてください(違)。


(let ((a (cons + ())))
  (set-cdr! a (list a))
  ; (display a)
  (eval a (interaction-environment))

サイクルなS式を評価しようとすると、やっぱり反応がなくなるらしい(Gauche/Dr.Scheme)。


ruby でも似たようなことは出来るが、lisp だともうちょっと綺麗(ほんとか?)。

(define (f a) (+ 1 2))
(f (set! f (lambda (a) (+ 1 2 3))))

Dr.Scheme だと 3。Gauche だと 6。要するに、関数の評価順序の問題。んで、要するにこんな書き方はするなって意味だ。

応用例(何の)

(define f ())
(f (set! f (lambda (a) (+ 1 2))))

WORM_SOBIG.F というのがたくさん着てるらしい。うーん。


う・・・、再帰を使わないScheme の実装って難しいな・・・。

env.rb っての作って require したら、標準ライブラリのほう呼んでやんの。わからずに10分くらい悩んだ。

あかんなぁ。if がむっちゃ難しい。


また馬鹿。10分くらい悩んだ。

class C
  Stored = C.new
  def self.set_store key,val
    Stored.set key,val         # Error!!
  end

  def initialize
    @hash = {}
  end
  def set key, val
    @hash[key] = val
  end
end

これは落とし穴だろー、ってこんなことしないか?


if はやっぱりフックしないとだめかしらん。再帰って偉大だな。

やっと算数が出来るようになった。


Module Test::Unit::Assertions これを適当に組み合わせて使うのか。


研究会で和歌山まで行くんですが、一泊二日の慌しさ。うーん、ゆっくりしたいぞ。


うー、やっぱり酔っ払ってるとハックできない・・・。nokadaさんへの道はまだまだ遠い。

_shiro(Tue Sep 02 17:52:39 JST 2003)

 write* して下さい。なお、この表示フォーマットはCommonLispで使われており、SchemeではSRFI-38で規定されています。Gaucheはまだ読み込みの方には対応していません。

_ささだ(Tue Sep 02 18:33:42 JST 2003)

 なるほど。Common Lisp やっぱり仕様がでかいだけあるんですね。

_新潟のS(Tue Sep 02 23:24:45 JST 2003)

 Chez Schemeも循環リストを回避するみたい。MacSchemeだったかPCSchemeはストップするまで表示してたような。

_nobsun(Tue Sep 02 23:57:42 JST 2003)

 そういえば、循環リストを検出するには、という有名なクイズがありましたね。対象とするリスト以外は使ってはいけない。副作用もだめ。というやつ。

_shiro(Wed Sep 03 04:59:50 JST 2003)

 循環リストの検出、spine方向だけなら1つ飛びに進むsentinelを使うのがポピュラーだと思うのですが、tree(というか一般のDG)でもそれ出来るんですか?

_nobsun(Wed Sep 03 06:48:00 JST 2003)

 当該ノードより先にある部分については単に子について同じことを繰り返せばいいだけだと思いますが。あれなんか勘違いしてるかな(>儂)

_nobsun(Wed Sep 03 09:55:12 JST 2003)

 children を集める必要があるからだめかなぁ。

_1(Mon)

おいおい、9月だよ・・・。


(define (f)
  (define (cf)
    (+ 1 2))
  (set! + -)
  (cf))

gauche では 3。これは、パース時に NUMADD にしてしまうからなんでしょうね。いや、(+ 1 2) を 3 にしてるのか。パース時に。

問題無いんだろうけど(誰もこんなことシネーヨ)、仕様はどうだったかな。


継続の話。

複数作った継続って、環境を共有できるものはしないといけないんだっけ?

(define x ())
(let ((t ()))
  (if (call-with-current-continuation (lambda (c) (set! x c)))
      (display t))  ;; <<== A
  (set! t 10))

(x #t) ; goto A

gauche, mit-scheme, chez-scheme と、10 が返りました。共有してます。(ちなみに MIT-Scheme はとまんねー(笑))

ruby で似たように作ると、nil です。つまり、環境は共有しません。勿論そのように作っており、ruby での continuation はそういうものですので、そうなるのが当然です。

が、環境をきちんと共有しないといけないならば、rucheme は ruby の callcc を単純に使ってるだけなので、ダメダメであるということになります。


バカ。

class String
  def m
    [3] # self[3] とやりたかったらしい。
  end
end

5分くらい悩んでしまったらしい。


うう、駄目だ。「リファクタリング」買おう・・・。


なぜか今日一日 C++ で高速化に頭を悩ませる。てきとーにインライン化したら遅くなってしまった。


わ、また ruby-list に未読がたくさん!

_さかい(Mon Sep 01 22:58:47 JST 2003)

あれ?、Rubyでも環境は共有されるのでは? 以下のコードを実行したら、ちゃんと10が返ってきましたよー

x = nil

lambda{|t|
  if callcc{|c| x = c; nil }
    p t
    exit
  end
  t = 10
}.call(nil)

x.call(true)
_ささだ(Tue Sep 02 00:11:52 JST 2003)

 あれ、私はどんな例を試したんだろう? ただ寝ぼけてただけかも。

_ささだ(Tue Sep 02 00:17:38 JST 2003)

 そうだよなぁ、これが出来ないとスレッド分けられないよなぁ。

Sasada Koichi / sasada@namikilab.tuat.ac.jp
$Date: 2003/04/28 10:27:51 $