JavaScript でのたらいまわしいろいろ2006年12月04日 23時47分

IT戦記 - JavaScript で遅延評価」より。遅延評価といえばたらいまわし関数と相場が決まっている、ような気がする。

function tak(x, y, z) {
  return (x <= y) ? y : tak(tak(x - 1, y, z),
                            tak(y - 1, z, x),
                            tak(z - 1, x, y));
}

これを元記事に従って書き直すとこうなる。

// from http://d.hatena.ne.jp/amachang/20061204/1165180769
Function.prototype.lazy = function () {
  return { valueOf: this };
};

function takL(x, y, z) {
  return (x <= y) ? y :
    takL(takL(x - 1, y, z),
         takL(y - 1, z, x),
         function () { return takL(z - 1, x, y); }.lazy());
}

print(takL(10, 5, 0));

だが、Wikipedia で遅延評価の項を見てみると計算結果をキャッシュしておかなくてはいけないようだ。なのでキャッシュの仕組みを取り入れてみる。

Function.prototype.delayed = function () {
  var self = this, args = arguments, value = undefined, forced = false;
  return {
    valueOf: function () {
      if (!forced) {
        value = self.apply(null, args);
        forced = true;
      }
      return value;
    }
  };
};

function takD(x, y, z) {
  return (x <= y) ? y :
    takD(takD(x - 1, y, z),
         takD(y - 1, z, x),
         takD.delayed(z - 1, x, y));
}

print(takD(10, 5, 0));

lazy のようにワンクッション入れるのは嫌だ、キャッシュもなくていいという場合は、変形が多くなるが関数式だけでも事足りる。

function takF(x, y, fz) {
  return (x <= y) ? y :
    takF(takF(x - 1, y, fz),
         takF(y - 1, fz(), function () { return x; }),
         function () { return takF(fz() - 1, x, function () { return y; }); });
}

print(takF(10, 5, function () { return 0; }));

ついでにメモ化版。

function takM(x, y, z) {
  var item = x + "," + y + "," + z; // [x, y, z].join() より速い
  return (item in takM.memo) ? takM.memo[item] :
    takM.memo[item] = (x <= y) ? y : takM(takM(x - 1, y, z),
                                          takM(y - 1, z, x),
                                          takM(z - 1, x, y));
}
takM.memo = {};

print(takM(10, 5, 0));

そして各たらいまわし関数の速度比較。SpiderMonkey のシェルで試してみると takF がもっとも速く、ついで takL に takD、大きく差を開けて takM という結果になった。ブラウザ上では安定した結果が得られなかったものの、takF、takL、takD が総じて速く、takM はその 2~3 倍時間がかかった。

まとめると、JavaScript でのたらいまわしに限って言えば、関数式を使い評価を遅らせることが速度向上に大きく貢献している。そしてその際計算結果をキャッシュしておくかどうかはあまり関係ないようだ。メモ化はそれに比べれば遅いものの、何もしない場合と比べれば月とスッポンの差がある。

ちなみに、JScript ではなぜかそのままメモ化するよりもメモ化を汎用化したほうが速かった。

Function.prototype.memoize = function () {
  var self = this, memo = {};
  return function () {
    var item = Array.prototype.join.apply(arguments);
    return (item in memo) ? memo[item]
                          : memo[item] = self.apply(this, arguments);
  };
};

function takMG(x, y, z) { // same as tak
  return (x <= y) ? y : takMG(takMG(x - 1, y, z),
                              takMG(y - 1, z, x),
                              takMG(z - 1, x, y));
}
takMG = takMG.memoize();

「あの生徒が使ったあの『あれ』は……」2006年12月08日 01時36分

WebKit の Bugzilla では検索結果一覧のページに今日の一言みたいな感じで何かしらのフレーズが出てくるのだが、その中に She, where he had had 'had', had had 'had had'. 'Had had' had had the approval of the examiner. というものがあった。"The teacher said that that 'that' that that student used was incorrect." みたいなものか。文をまたいで had が実に 11 連続。意味が取れない。

最近読んだもの (2006 年 12 月)2006年12月22日 00時48分

積読がどんどん増えていきます。正月にどれだけ消化できるでしょうか。

戦う司書と恋する爆弾 (山形石雄)

タイトル買いが成功。「戦う司書」は置いといて、「爆弾」――人間爆弾に改造され、人の心を奪われた少年――の恋する様がすばらしいです。決して手の届かないところにいる二人が、お互いを心の芯に据え行動するという構造が見事。

小公女 (バーネット、伊藤整訳)

アニメ『奏光のストレイン』(登場人物の名前が小公女から採られている) が面白かったところに、たまたまブックオフで見かけたので購入。主人公の名前が「サアラ」となっているのはすべて「セーラ」に脳内変換して読みました。何というか、妄想想像力の勝利ですね、これは。つらい境遇に落ちた少女が想像力を働かせ耐え忍んでいたら、財産が転がり込んできて想像が現実になりましたよというお話です。何が面白いかといえばサアラが単なる聖人君子ではないところ。人形は人形でしかなく、動き出して自分を慰めてくれないのは仕方のないことだという例えに「ラヴィニアやジェッシイにものがわからないのと同じことなのね」と言ってのけるあたり黒すぎます。

読み終わったあとで青空文庫菊池寛訳があるのに気づいたのですが、これがまたすごい。「宮様」と書いて「プリンセス」とルビが振ってあります。それならタイトルも「小宮様」とすべきではと思うのですが、なぜかそこだけは「小公女」。伊藤整訳で「肉まんじゅう」となっている食べ物が何なのか思っていたら、こちらでは「肉饅頭(ミート・パイ)」となっており疑問が解けました。

わたしたちの田村くん (竹宮ゆゆこ)

タイトルだけ見てハーレム物かと遠慮していたのですが、泣けるという話を聞いて手に取ってみました。……自分の過去と照らし合わせて心に突き刺さってきます。文章はあまり好みではありませんがストーリーを思い起こすとじわじわときます。私に田村くんの 10 分の 1 の甲斐性でもあったならばと中高生時代の自分を呪わずにはいられません。いや、当然のごとく板ばさみの恋に悩まされることなど欠片もなかったんですが。いろいろな意味で走ってこその青春ということを再認識させてくれます。

それにしても、この作品に限らず、皆さん遠めに見ただけの人物をよく覚えていますね。元来人の顔と名前を覚えられず、佐々木倫子の忘却シリーズを読んだときにこれは自分だと確信した私にとっては、まったくうらやましいを通り越して感心するばかりです。そんな私は那州雪絵の至言「もてたかったらまず忘れてはいけない」をかみ締めて今日も生きていくのでありました。

よくわかる現代魔法 (桜坂洋)

  1. よくわかる現代魔法
  2. よくわかる現代魔法―ガーベージコレクター
  3. よくわかる現代魔法―ゴーストスクリプト・フォー・ウィザーズ
  4. よくわかる現代魔法―jini使い
  5. よくわかる現代魔法―たったひとつじゃない冴えたやりかた

サブタイトルにひかれて購入。GhostscriptJini は全然使ってないけどガベージコレクタには日ごろから大変お世話になっています。「たったひとつじゃない冴えたやりかた」に TMTOWTDI がかけてあるのはうまいと思ったけど本文には出てきません。ドジな女子高生が、コンピュータを駆使して「コード」を組み上げる「現代魔法」と関わっていくお話です。

コンピュータネタはわかるけどゲームネタ (?) はよくわからず。どうも全体的にネタの組み込み方が甘く、そのネタを知らないと楽しめないつくりになってしまっているような気がします。それから主人公の友人の C と Perl ができる女子高生に違和感が。単にプログラミングができるというだけなら別にいいんですが、スナックと炭酸飲料を好む生活態度まで Geek な女子高生というのはちょっとね……。案外そういう女子高生もいたりするんでしょうか?

主人公の使う魔法にたらい―― TV のコントで降ってくるような金たらい――の召喚があるのですが、ちょうどたらいを回した後だったのでこれには大笑い。師匠の専門は関数型言語ときましたし、これは最後には遅延評価による高速たらいまわしとかでてくるんですよね!? 遅延で高速というのも字面だけ見ると妙な話ですが。

しかしコンピュータネタメインのライトノベルというのはなかなかないですよね。水無月ばけらあたりが『友井町セキュリティホールバスターズ』なんて書いてくれたら絶対に買うんですが。

Firefox 2 へ移行2006年12月22日 00時51分

Firefox 2.0.0.1 が出たので常用のブラウザを Firefox 1.5 系統から 2 系統へと移しました。それに伴い、ブックマークと拡張機能の整理を決行。userChrome.js のおかげで拡張の数を大幅に減らすことができました。以下移行に伴い削除した拡張の一覧。

Copy URL +
Launchy
Paste and Go 2
Right Encoding
TabScroller
Tabs Open Relative
Zone Identifier Extension
userChrome.js で代替。
Link Alert
userContent.css で代替。
Sage
livedoor Readerはてなアンテナに移行。
undoclosetab
本体にて実装。

Link Alert の代替としたスタイルシート (Windows 用) は以下のとおりです。新しいウィンドウを示す適当なアイコンが見当たらなかったので exe のを流用。ツールバーの項目にある「新しいタブ」のアイコンが使えるといいのですが、大きな画像の一部を使う手立てはあるのでしょうか?

/* 特殊なリンクに対するマウスカーソルを変更する */
:-moz-any-link[target="_blank"] {
  cursor: url("moz-icon://.exe?16"), pointer !important;
}
:-moz-any-link[href$=".pdf"] {
  cursor: url("moz-icon://.pdf?16"), pointer !important;
}
:-moz-any-link[href^="javascript:"], :-moz-any-link[href="#"][onclick] {
  cursor: url("moz-icon://.js?16"), pointer !important;
}
:-moz-any-link[href^="mailto:"] {
  cursor: url("moz-icon://.eml?16"), pointer !important;
}

CSS だけで画像を切り抜く2006年12月26日 22時14分

海馬日記 - data: URIでユーザスタイルシートに畫像を埋込む」より。リンクの種類を表すアイコンをつける話について。

まあその方法 (data URI を使う) が一番妥当でしょうね。ちなみにカーソルではなくリンクの前に埋め込むのなら一応 data URI を使わずともできます。

:-moz-any-link[target="_blank"]:before {
  content: "";
  font-size: 0;
  padding-left: 16px;
  padding-top: 14px;
  background: url("chrome://browser/skin/Toolbar-small.png") -160px -16px;
}

ディセンダの高さを 2px に決め打ちしているのがいかにも気持ち悪いですが。padding-top の替わりに font-size: 16px とすればこの気持ち悪さはなくなりますが、今度は拡大縮小に伴って切り抜き部分の高さが変わってしまいます。Gecko が display: inline-block に対応してくれれば解決すると思うんですけどね。

Bug 9458 および Bug 368622 の修正により display: inline-block が無事動作するようになりました。Firefox 3 以降は以下でいけるはずです。

:-moz-any-link[target="_blank"]:before {
  content: "";
  display: inline-block;
  width: 16px;
  height: 16px;
  background: url("chrome://browser/skin/Toolbar-small.png") -160px -16px;
}

余談ですが、data URI のデータ部分は RFC 2397*urlchar と定義されています。で、urlcharRFC 2396 からって書いてあるんですが、RFC 2396 にはどこにも urlchar なんて定義されていないんですよね。一番それっぽいのは uric なんですが、果たしてこれはどこかで訂正されているのでしょうか。……などと思っていたら SuikaWiki に詳しい解説がありました。このこと以外にもいろいろと穴のある仕様なんですね。