生姜
生姜の匂いを「冬を感じる優しいかおり」と表現しているのを見てなんかぐっときた。
生姜の匂いを「冬を感じる優しいかおり」と表現しているのを見てなんかぐっときた。
3部作の完結のフルアルバムがでた。数日聴きこんでみたけど、「Groria Street から愛を込めて#3 」(原文ママ) が素晴らしい。「ただ生きるよりルール」
「Apple star storyS」 はヘッドフォンで聴くと面白い。ライブ音源もいいけどこれも好き。Most beautiful in the world にはASの歌詞がついてなくて、聴きとってテキストにしといたのだけど、何いってのかよくわかんなくてなんとなくで書いたりしたところがあった。でも答えあわせをしたら割とあってた (鍵カッコつけた部分まであってて笑った)。(「星空」を「この空」とまちがえてた (シャウトしててききとれない)。「たまにわからなくなるけど」を「たまにわからなくなるねと」とまちがえてた (なんで間違えたのかわからないけどw))
「そして列車は行く」はなんか長い部分を見ていろいろカッコいい。うまくいえない。曲としてめっちゃカッコいいのもそうだし、「今 拍手喝采とか涙よりもっと」とか、いちいちかっこいい。
「記憶と記録」は四人のゴブリン大いに踊るに収録されていた「微笑とメロディー」のリアレンジなんだけど、このアレンジがなんか想像の斜め上をいきまくってておもしろい。
でもって「黄金の鐘」なんだけど、最初の歌詞から大分歌詞が変わってて残念なところがあったりするけど、聴いてるとどうでもよくなってきた。これはたぶん聴きこむともっとじわじわきそうだなぁ。
ツインドラムがかっこいいからライブでききたいなぁ……
(動いてはいるけど、ちょっと挙動が思ったとおりでない気がする (巨大なループのあと、次のプロセスへ進むのが遅い気がする) のでコードを考えなおしのために現在の実装をメモ書きします) なんか jQuery Deferred って書くと jQuery Core に Deferred システムがあるみたいにみえるけどちがうよちがうよ。でも内部的には animate あたりで必要だから持ってるんだとおもう……
MochiKit Deferred では子と親がはっきりわかれていて、子をつくるときには親を pause し、子が実行しおわったら親の pause を解除するようになっています (だと思うけど、実はあんまり使ったことなくてわからない)。これは、MochiKit の Deferred が Array でチェインを持って処理をしていて、子 (もまた Array でチェインをもっている) がかえされたとき、こうするのが一番だからだと思います。
jQuery Deferred では子も親もはっきりわかれておらず、子 Deferred が出現したら、現在の継続を子 Deferred の継続にし、親はもう過去の存在となるような実装にしています (親には戻らない)。そういうアレで pause がないです。
jQuery Deferred は一個の Deferred は一個のコールバックしか持ちません。処理のプロセス一つをパッケージングし、次のプロセス (を Deferred でパッケージしたもの=継続) を持っています。Deferred.prototype.next(fun) は fun を this のプロセスとし、さらに新しく Deferred をつくり、新しく Deferred を作り、そのプロセスを fun とし、それを this の継続として設定する関数です。
// global function next
next(function () {
console.log(["chain", 1]);
}).
// Deferred.prototype.next
next(function () {
console.log(["chain", 2]);
});
// 定義ずみの関数
/*
function next (fun) {
// 新しく呼ばれることが約束された Deferred をつくる
var d = new Deferred();
setTimeout(function () { d.call() }, 0);
// fun をその Deferred のプロセスとして設定し返す。
d.callback.ok = fun;
return d;
}
*/うえのコードは
// あとで呼ばれることが約束された Deferred を作成
d1 = next(function () {
console.log(["chain", 1]);
});
// 次のプロセスをパッケージする Deferred を作成
d2 = $.deferred(); // (Deferred をエクスポートしてないので new Deferred() とはできません。
// プロセスを設定
d2.callback.ok = function () {
console.log(["chain", 2]);
};
// d1 の継続を d2 に設定
d1._next = d2;と同じです。
子 Deferred の例をだしてみます。
next(function () {
console.log(["child", 1]);
return next(function () {
console.log(["child", 2]);
});
}).
next(function () {
console.log(["child", 3]);
});このように Deferred をコールバックで返すと、コールバックを実行した Deferred は返された Deferred の継続に自分の継続をセットし、自分ではなにもしません。
next(function () {
console.log(["child", 1]);
ret = next(function () {
console.log(["child", 2]);
});
ret._next = this._next;
this.cancel();
}).
next(function () {
console.log(["child", 3]);
});これと全く一緒です。
実装では以下のようになっています。
call : function (val) { return this._fire("ok", val); },
fail : function (err) { return this._fire("ng", err); },
_fire : function (okng, value) {
// if (typeof log == 'function') log("_fire called");
var self = this;
var next = "ok";
try {
value = self.callback[okng].call(self, value);
} catch (e) {
next = "ng";
value = e;
}
if (value instanceof Deferred) {
value._next = self._next;
} else {
setTimeout(function () {
if (self._next) self._next._fire(next, value);
}, 0);
}
}_fire が実際にコールバックしている関数です (この関数は call/fail から間接的に呼びます)。コールバックの返り値が Deferred のインスタンスの場合は、それの _next を設定しているだけです。それ以外の場合は setTimeout を通して継続をよびだしています (setTimeout をつかっているのは、永遠とコールバックチェインが続くとスタックオーバーフローになるからです)。
jQuery Deferred では一つしかプロセスをもっていないと書きましたが、実際のところエラーを処理するためのコールバックも持っています。とりあえず例をだすと (テストケースから)
next(function () { throw "Error"; }).
error(function (e) {
expect("Errorback called", "Error", e);
return e; // エラーのリカバリー
}).
next(function (e) {
// next だけど、リカバリーされたので実行される。
expect("Callback called", "Error", e);
// また投げてみる。
throw "Error2";
}).
next(function (e) {
// エラーがリカバリーされていないのでよばれない。
ng("Must not be called!!");
}).
error(function (e) {
// エラー専用のチェインをたどりここまでくる。
expect("Errorback called", "Error2", e);
});コールバックで発生したエラーはエラー専用のチェインをとおります。また、エラーバックでエラーを処理し、値をなげなおすことで、後続の処理を続けることができます。
このエラー専用のチェインですが、単に throw をくりかえすだけのチェインです。Deferred は以下のように初期化されれ、デフォルトのコールバックを持っています。
init : function () {
this.callback = {
ok: function (x) { return x },
ng: function (x) { throw x }
};
this._next = null;
},デフォルトでは ng は常に throw をするため、前途の _fire の catch に捉えられ、継続の ng を実行するように伝えられます。エラーのチェインへの分岐は throw するかしないかなので、エラーバックで普通に return すればエラーのリカバリーになります。
なんかつかめそうでつかめない。どっかおかしいような気がする。頭悪いのがむかつく
あーわかった。わかった。next で呼ばれる Deferred を一個余計につくっていたせいだった。
http://coderepos.org/share/changeset/2287
で修正した。ついでに説明も修正した。テスト書いといてよかった……役にたった (テストも Deferred 自身で書かれているから、あきらかにおかしいときはテストの数があっているかどうかをみる)
じわじわくる!!
http://svn.coderepos.org/share/lang/javascript/jquery-deferred/sample.html
http://jquery.com/plugins/project/deferred
いろいろサンプル書いてつかいみちを考えているとたのしい。
var list = [];
list.push($.get("a.html").next(function (data) { return data.match(/<title>([^<]+)<\/title>/) } ));
list.push($.get("b.txt" ).next(function (data) { return data.match(/##\s*([^<]+)\s*##/) } ));
list.push($.getJSON("c.json").next(function (data) { return data.title } ));
parallel(list).next(function (values) {
print("Titles "+values.join(", "));
});みたい書ける。たのしい。(うえのコードがうごくかはためしてない)
それぞれ、べつべつのフォーマットのリソースをとってくる。タイトルを抽出するところまでは個々の Deferred が処理して、そいつらを parallel (DeferredList) であつめてくる。
でもそういうふつうの (謎) 非同期処理より、ループの分割のほうがおもしろい。
loop({begin: 1, end:100, step:10}, function (n, o) {
print(["Processing devided loop:n=", n].join(""));
for (var i = 0; i < o.step; i++) {
var j = n + i;
print(j);
}
});
function print (m) { $("#loop-code1").append("\n// "+m) }1 から 100 までをループする。ただし最大 10 個に制限して分割してループする (o.step を条件にしているのは、境界付近でよしなにするため。最後 (o.last == true) 以外は常に渡した step と一緒)。定期的にブラウザに処理がもどるので固まったようにならない (100 ぐらいじゃ固まらないけど)。固まりさえしなければある程度時間がかかってもストレスがたまらないから嬉しい。
ディレイいれながらループも簡単にかける
loop(5, function (i, o) {
print(i);
return o.last? i : wait(1);
}).
next(function (e) {
print("end ["+e+"]");
});1秒ずつまちながら 5 回ループする (0,1,2,3,4)
最後の値を次へ渡したいので条件をいれてる。end [4] と最後にでる。
ぼくはわからないことがあるとすぐ日記に書こうとする。「だれかおしえてくれないかなー」と思う。でもそれと同時に、この程度がわからないと思われるのは悔やしいと思う。なので日記を書いている途中で、調べに戻って、解決したりする。最初に「これがわからない」と書いてから、ins 要素を書くまではかなり必死に集中する (誰かが教えてもらうまえに「わかった!」と書きたい)。もちろん結局わからないこともあるけど、日記に書こうとすることで、回転の悪い頭を最大限回すことができる。ついでに「何がわからないか」を文章にすることで明確にできて、書きているうちに普通に解決してしまう場合もある。だから、「わからない」と書いたはいいけど、日記として残らず消えていった文章もある。
p({ foo: "abc", bar: "def" })こうかけるやつなんだけど、JS みたいなノリで
p({ foo : "abc", bar : "def" })と書くとパースエラーになる。
シンボルキーと他のキーは同時に書けるけど、ちょっと混乱するかもしれない
p({ foo: "abc", bar: "def", "baaa" => "aaa" })それに、うえのように書いても "baaa" と :baaa は違うオブジェクトなので
p foo[:baaa] #=> nil p foo["baaa"] #=> "aaa"
self == -> { self }.()(もちろんまちがってないけど) true だしなぁ。
引数かえられないけど redo で現在のメソッドを最初からやりなおすのはできる……
Binding#callee とか実装できないかなぁ (実行中の Method/Proc をかえす)
フィルタの適用方法を変えて、importNode されたノード個々に対してフィルタを適用するようにした。本家と挙動が違うかもしれない。(フィルタ書いたことなくてよくわからない)
でもってはてなスターがロードされているページではデフォでスターをロードするようにした。Hatena.Star に特定ノード以下に制限してロードするのがあったのでそれつかってみた。(はてダのクイックページャのソースからたどった)
直書きだと、バージョンアップするたびにコピペが発生してめんどい。どうにかしたい。
MochiKit の Deferred がよくできてるなぁと実感する。Deferred チェイン中に Deferred return するとチェイン中断して……みたいなのがかっこいい (そういうのを Deferred 一個で統一してできるようにしているので MochiKit Deferred は結構サイズが大きい)。でも API がどうしても好きになれない。jQuery に移植したい。
でも慣れないとよくわからないよなぁ……(setTimeout の挙動 (ブラウザの実行キューのほげほげ) とかをわかってないと、Deferred つくってるところで setTimeout(, 0) してて、なにこれ? っておもうことになる。)
MochiKit の実装はもっとシンプルにできそうなのでつくってみた。でもいろいろ頭悪くて考えきれてないと思う……
例えばこういう風に書けるようにする。
wait(1).
next(function (e) {
log([1, e]);
return wait(1).next(function (e) {
log([2, e]);
return wait(2).next(function (e) {
log([3, e]);
});
});
}).
next(function (e) {
log(4);
return "555";
}).
next(function (e) {
log(e);
})末尾再帰っぽいの (return call ってのが tailcall っぽくてよくないですか><)
next(function () {
log("start");
}).
next(function () {
function pow (x, n) {
function _pow (n, r) {
if (n == 0) return r;
return call(_pow, n - 1, x * r);
}
return call(_pow, n, 1);
}
return call(pow, 2, 10);
}).
next(function (r) {
log([r, "end"]);
}).
error(function (e) {
alert(e);
})実装
function Deferred () { this.init.apply(this) }
Deferred.prototype = {
init : function () {
this.callback = {
ok: function (x) { return x },
ng: function (x) { throw x }
};
this._next = null;
},
next : function (fun) { return this._post("ok", fun); },
error : function (fun) { return this._post("ng", fun); },
call : function (val) { return this._fire("ok", val); },
fail : function (err) { return this._fire("ng", err); },
cancel : function () {
this._next = null;
},
_post : function (okng, fun) {
this.callback[okng] = fun;
this._next = new Deferred();
return this._next;
},
_fire : function (okng, value) {
var self = this;
var next = "ok";
try {
value = self.callback[okng].call(self, value);
} catch (e) {
next = "ng";
value = e;
}
if (value instanceof Deferred) {
value._next = self._next;
} else {
setTimeout(function () {
if (self._next) self._next._fire(next, value);
}, 0);
}
}
};
function wait(n) {
var d = new Deferred();
var t = new Date();
setTimeout(function () {
// 実際にかかった時間をコールバック
d.call((new Date).getTime() - t.getTime());
}, n * 1000)
return d;
}
function ps () {
var d = new Deferred();
setTimeout(function () { d.call() }, 0);
return d;
}
function next (fun) {
return ps().next(fun);
}
function call (f, args) {
args = Array.prototype.slice.call(arguments);
f = args.shift();
return next(function () {
return f.apply(null, args);
});
}なかなかカッコいい感じがする。もうちょいいじる。
next は this ではなくて、次の Deferred (this が準備できたらよばれる Deferred // _next) をかえす。これでずっとチェインしていく。もしコールバックが Deferred をかえしたら、その Deferred に _next をわたしてあげる。_next は継続 (ていっていいのかな。継続をちゃんと理解していない)
スタック消耗してたのを修正した
function loop (o, fun) {
var begin = o.begin || 0;
var end = o.end;
var step = o.step || 1;
var ret;
return next(function () {
function _loop (i) {
if (i < end) {
ret = fun.call(this, i, step);
return call(_loop, i + step);
} else {
return ret;
}
}
return call(_loop, begin);
});
}
next(function () {
var hoge = 0;
return loop({end:50000, step:50}, function (n, step) {
for (var i = 0; i < step; i++) {
hoge += n+i;
}
return hoge;
});
}).
next(function (e) {
log(e);
log("end");
}).
error(function (e) {
});50000回のループを50ずつ実行する。