2007年 11月 30日

Ruby1.9 のシンボルキーハッシュリテラルの簡易記法

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"

Ruby で arguments.callee ってどうやるんだろ

self == -> { self }.()

(もちろんまちがってないけど) true だしなぁ。

引数かえられないけど redo で現在のメソッドを最初からやりなおすのはできる……

Binding#callee とか実装できないかなぁ (実行中の Method/Proc をかえす)

jAutoPagerize / はてなスター

フィルタの適用方法を変えて、importNode されたノード個々に対してフィルタを適用するようにした。本家と挙動が違うかもしれない。(フィルタ書いたことなくてよくわからない)

でもってはてなスターがロードされているページではデフォでスターをロードするようにした。Hatena.Star に特定ノード以下に制限してロードするのがあったのでそれつかってみた。(はてダのクイックページャのソースからたどった)

GM の config

直書きだと、バージョンアップするたびにコピペが発生してめんどい。どうにかしたい。

最近のまいぶーむ -> MochiKit Deferred の再発明

MochiKit の Deferred がよくできてるなぁと実感する。Deferred チェイン中に Deferred return するとチェイン中断して……みたいなのがかっこいい (そういうのを Deferred 一個で統一してできるようにしているので MochiKit Deferred は結構サイズが大きい)。でも API がどうしても好きになれない。jQuery に移植したい。

でも慣れないとよくわからないよなぁ……(setTimeout の挙動 (ブラウザの実行キューのほげほげ) とかをわかってないと、Deferred つくってるところで setTimeout(, 0) してて、なにこれ? っておもうことになる。)

Deferred チェイン。

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 は継続 (ていっていいのかな。継続をちゃんと理解していない)

スタック消耗してたのを修正した

Deferred loop

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ずつ実行する。

2007年 11月 29日

門田匡陽

なんかこう、ずっとひっかかってたけど、門田氏とRitaさんが微妙に唄いかたが似てることに気付いた。黄金の鐘聴いてて思った。

JavaScript tailcall...

function Process () {
	this.init.apply(this);
}
Process.prototype = {
	init: function () {
		var self = this;
		this.stack = [];
		this.rvalue = undefined;
		setTimeout(function () { self.call() }, 0);
	},

	p: function (f) {
		this.stack.unshift(f);
		return this;
	},

	call: function () {
		var self = this;
		var f = this.stack.pop();
		var thisObj = {};
		thisObj.call = function (f, args) {
			args = Array.prototype.slice.call(arguments);
			f    = args.shift();
			self.stack.push(function () {
				return f.apply(thisObj, args);
			});
			return "this";
		};
		this._rvalue = f.call(thisObj, this._rvalue);
		if (this.stack.length) {
			setTimeout(function () { self.call() }, 0);
		}
	}
};

window.onload = function () {
	var ps = new Process();

	ps.p(function () {
		$("#content").append("<div>start!</div>");
	}).p(function () {
		function pow (x, n) {
			function _pow (n, r) {
				$("#content").append("<div>"+[n, r]+"</div>");
				if (n == 0) return r;
				return this.call(_pow, n - 1, x * r);
			};
			return this.call(_pow, n, 1);
		}
		return this.call(pow, 2, 1000);
	}).p(function (r) {
		$("#content").append("<div>end!"+r+"</div>");
	});
};

nemui

Groria Street から愛を込めて#3

なんかくせになってきた。これすごい好きだ。「捨てたものを~」のところが鳥肌たつぐらい好きだ。

CD はずすと曲目と一緒に年号(のような4桁の数字)が書いてあるけど、これなんだろう。

gerry++

きのうもだったけど……

2007年 11月 28日

Ruby1.9 のラムダさん

やばいやばい。知らなかった。手元で既に使えるシンタックスっていう! (でも将来使えるかわからない予感) id:secondlife さんに教えてもらった。id:secondlife++ あと parse.y をながめてやりかたを覚えたw

この前の true/false のラムダを書いてみる。

# curry は http://subtech.g.hatena.ne.jp/cho45/20071119/1195420784

# 1.8
t = lambda {|x, y| x }.curry
f = lambda {|x, y| y }.curry

t[lambda {
	puts "hoge"
}][lambda {
	puts "fuga"
}][]

#1.9 head
t = -> (x, y) { x }.curry
f = -> (x, y) { y }.curry

t[-> {
	puts "hoge"
}
][-> {
	puts "fuga"
}][]

# or
t.
(-> {
	puts "hoge"
}).
(-> {
	puts "fuga"
}).()

やばすぎる萌えすぎる。


メモ

t = -> (x, y) { x }
t = -> x, y { x }   # 括弧いらないらしい

(1..3).map {|x| x * x }
(1..3).map(&-> x { x * x }) # このつかいかたはあんましなそう?
(1..3).map &-> x { x * x }  # おなじ

car = -> x,*xs { x }
cdr = -> x,*xs { xs }
p car[10, 20, 30] #=> 10
p cdr[10, 20, 30] #=> [20, 30]

car = -> ((x,*xs)) { x }
cdr = -> ((x,*xs)) { xs }
p car.([10, 20, 30]) #=> 10
p cdr.([10, 20, 30]) #=> [20, 30]

どういうとき一番うれしいかなぁ。ラムダ計算のやつは普通書かないし

hoge = ->&b{ b.yield b }

hoge.() {|x|
	p x.lambda? #=> false
}

hoge.(&->x{
	p x.lambda? #=> true
})

これ記法によって挙動が変えられるってことで夢ひろがりんぐだけど、実際変わるメソッドがあったりするとびびりそう。どういう意図で入ってるんだろう。

Ruby1.9 のラムダさん 2 (SKI とチャーチ数 256)

#!ruby1.9 -v

s = -> x {-> y {-> z { x.(z).(y.(z)) } } }
k = -> x {-> y { x } }
i = -> x { x }

t = k
f = s.(k)

car = -> list { list.(t) }
cdr = -> list { list.(f) }

car = s.(i).(k.(t))
cdr = s.(i).(k.(f))

# ((lambda (n) (n n)) ((lambda (n) (n n)) (lambda (f x) (f (f x)))))
cn256 = -> n { n.(n) }.(-> n { n.(n) }.(-> f {-> x { f.(f.(x))}}))
# SII(SII(S(S(KS)K)I))
cn256 = s.(i).(i).(s.(i).(i).(s.(s.(k.(s)).(k)).(i)))

inputlist = -> list {
	-> f { f.(list.first || cn256).(inputlist.(list.drop(1))) }
}


cn2num = -> cn { cn.(-> x { x + 1 }).(0) }
num2cn = ->  n { -> f {-> x { (1..n).reduce(x) {|r,_| f.(r) } } } }

il = inputlist.([72, 101, 108, 108, 111].map(&num2cn))
p cn2num.(cn256)
p cn2num.(car.(il))
p cn2num.(car.(cdr.(il)))

Ruby のコードに見えないすぎるw

GDHM

黄金の鐘の歌詞があとかたもない。ハレルヤのところより看守は奴隷にパンを売りつけのところがなくなったのがすげー残念だなぁ。

Hash#put がほしい

class Hash
	def put(key, value)
		self[key] = value
		self
	end
end

a = { 1 => "foo", 2 => nil }
b = { 2 => "bar", 3 => "baz" }
p a.inject({}) {|r,(k,v)| r.put(k, b[k] || v) }

a.inject({}) {|r,(k,v)| r[k] = b[k] || v; r } # ← これがダサい

ML に投げるべきなんだろうなぁ……メールこわい……


というか []= が value を返すのはわかるけど、store (さっきしった) まで value かえさなくてもいいのに (Array#{push,unshift} は self をかえす)

jAutoPagerize / microformats hAtom

どういう風に入れようか悩んでて (autopagerize_insert_before は microformats っていうのかなぁ……じゃあ名前なにがいいんかなぁとかいろいろ) いれてなかったけど、コミットされてたのでまいっかー的に……(他人まかせ)

それとは別に hAtom と rel="next" による microformats のルールを入れた。link rel="next" もマッチすべきかも

, { url          : '^https?://.*'
  , nextLink     : '//a[@rel="next"]'
  , insertBefore : '//*[contains(concat(" ",@class," "), " hfeed ")]/following-sibling::node()'
  , pageElement  : '//*[contains(concat(" ",@class," "), " hfeed ")]'
  }

clear cache のメニュー追加をかかないとなぁとおもってたらコミットされてたww CodeRepos++

wiki clone

どうも wiki clone がつくれない。なんか考えることが多くて、しかもちらばってて、まとまらない。だめすぎる……

  1. 履歴管理と diff
  2. データの保存方法
  3. 記法パーサー
  1. データベースを使わない
  2. 全てのリビジョンをそのまま保存する (過去のは全部 gzip)
  3. diff は履歴表示のときだけ
  4. 記法なし

でつくってみればいいんだろうけど、いまいちやる気がわかない。こんなのつくっても、って感じ…… Ruby で blosxom クローンつくらなかったのもこういう理由なんだよなぁ……blosxom クローンを Ruby で書いても Ruby がある程度わかってるならあれじゃ学習にならないし、書くならまともなのが書きたかったから、プラグインシステムをどうするかでずっと悩んでた。

しかし wiki clone だとユーザの書きこみがあったりするから、他の言語で勉強しながらつくるっていうのは結構荷が重い……