パターンマッチング

http://www.geocities.jp/m_hiroi/xyzzy_lisp/abclisp22.html
この辺を読んで、javascriptに移植してみました。
これを使えば、うまいことマクロが書けるようになりそうです。
cdrとかの処理がいかにも遅そうなんですが、、、。
とりあえず、動けばいいのよ。動けば。


やっぱり、lispって凄いなぁと思います。
2chlisp,schemeスレのレベルも高いしなぁ。

<pre>
<script>
// リストの一番最初を返す
function car(list) {
	return list[0];
}

// リストの一番最初を取り除いたものを返す
function cdr(list) {
	var l = [];
	for (var i = 1; i < list.length; i++) {
		l[i - 1] = list[i];
	}
	if (l.length > 1 && l[0] == ".") return l[1];
	return l;
}

//
// 要素はパターン変数か
//
function variablep(pattern) {
	if (pattern == null) return false;
	if (typeof(pattern) == "object") return false;
	return (pattern.charAt(0) == "?");
}

function atom(pattern) {
	if (pattern == null) return true;
	if (typeof(pattern) != "object") return true;
	if (pattern.length == 0) return true;
	return false;
}

function consp(list) {
	if (list == null) return false;
	if (typeof(list) != "object") return false;
	if (list.length == 0) return false;
	return true;
}

//
// パターンマッチング : datum に変数は無し
//
function match (pattern, datum, binding) {
	if (variablep(pattern)) {
		return matchVariable(pattern, datum, binding);
	} else
	if (atom(pattern) && atom(datum)) {
		return matchAtoms(pattern, datum, binding);
	} else
	if (consp(pattern) && consp(datum)) {
		return matchPieces(pattern, datum, binding);
	} else {
		return null;
	}
}

//
// 変数とのマッチング
//
function matchVariable(var_, datum, binding) {
	var value = binding[var_];
	if (value) {
		// 値を使ってもう一度チェック
		return match(cdr(value), datum, binding);
	} else {
		// 変数束縛に追加する
		binding[var_] = datum;
		return binding;
	}
}

//
// アトム同士のマッチング
//
function matchAtoms(pattern, datum, binding) {
	if (pattern == datum ||
		(typeof(pattern) == "object" && pattern.length == 0 && typeof(datum) == "object" && datum.length == 0)) {
		return binding;
	} else {
		return null;
	}
}

//
// リスト同士のマッチング
//
function matchPieces (pattern, datum, binding) {
	var result = match(car(pattern), car(datum), binding);
	if(result == null) {
		return null;
	} else {
		return match(cdr(pattern), cdr(datum), result);
	}
}

Array.prototype.toString = function() {
	var r=[];
	for(var i = 0; i < this.length; i++) {
		if (typeof(this[i]) == "object") {
			r[i] = this[i];
		} else {
			r[i] = "\""+ this[i] + "\"";
		}
	}
	return "[" + r.join(",") + "]";
}

Object.prototype.toString = function() {
	var r=[];
	for(var i in this) {
		if (this[i] instanceof Array) {
			r[r.length] = "\""+ i + "\":"+this[i];
		} else {
			r[r.length] = "\""+ i + "\":\"" + this[i] + "\"";
		}
	}
	return "{" + r.join(",") + "}";
}

function p(str) {
	document.write(str + "\n");
}

function p2(l1,l2) {
	p(l1+","+l2);
	p(match(l1, l2, {})+"<hr />");
}

p2(["太郎","好き", "コーヒー"], ["太郎", "好き", "コーヒー"]);
p2(["太郎","好き", "?x"], ["太郎", "好き", "コーヒー"]);
p2(["太郎","?y", "コーヒー"], ["太郎", "好き", "コーヒー"]);
p2(["花子","?x", "?y"], ["花子", "好き", "紅茶"]);
p2(["太郎","?y", "コーヒー"], ["太郎", "好き", "ココア"]);
p2(["花子","?x", "?x"], ["花子", "好き", "紅茶"]);
p2(["taro","?ou", "ee"], ["taro", "xx", "ee"]);
p2(["for","?a", "?b"], ["for", ["a","b","c"], ["block"]]);
p2(["for",["paren","?a", "?b", "?c"], ["block", "?d"]],
	["for", ["paren", ["=", "i", "0"], "b","c"], ["block", "aa"]]);
p2(["for",["paren","?a", "?b", "?c"], ["block", "?d"]],
	["for", ["paren", ["=", "i", "0"], "b","c"], ["block", "aa", "ee"]]);
p2(["for",["paren","?a", "?b", "?c"], ["block", ".", "?d"]],
	["for", ["paren", ["=", "i", "0"], "b","c"], ["block", "aa", "ee"]]);
</script>
</pre>

結果

["太郎","好き","コーヒー"],["太郎","好き","コーヒー"]
{}
--------------------------------------------------------------------------------
["太郎","好き","?x"],["太郎","好き","コーヒー"]
{"?x":"コーヒー"}
--------------------------------------------------------------------------------
["太郎","?y","コーヒー"],["太郎","好き","コーヒー"]
{"?y":"好き"}
--------------------------------------------------------------------------------
["花子","?x","?y"],["花子","好き","紅茶"]
{"?x":"好き","?y":"紅茶"}
--------------------------------------------------------------------------------
["太郎","?y","コーヒー"],["太郎","好き","ココア"]
null
--------------------------------------------------------------------------------
["花子","?x","?x"],["花子","好き","紅茶"]
null
--------------------------------------------------------------------------------
["taro","?ou","ee"],["taro","xx","ee"]
{"?ou":"xx"}
--------------------------------------------------------------------------------
["for","?a","?b"],["for",["a","b","c"],["block"]]
{"?a":["a","b","c"],"?b":["block"]}
--------------------------------------------------------------------------------
["for",["paren","?a","?b","?c"],["block","?d"]],["for",["paren",["=","i","0"],"b","c"],["block","aa"]]
{"?a":["=","i","0"],"?b":"b","?c":"c","?d":"aa"}
--------------------------------------------------------------------------------
["for",["paren","?a","?b","?c"],["block","?d"]],["for",["paren",["=","i","0"],"b","c"],["block","aa","ee"]]
null
--------------------------------------------------------------------------------
["for",["paren","?a","?b","?c"],["block",".","?d"]],["for",["paren",["=","i","0"],"b","c"],["block","aa","ee"]]
{"?a":["=","i","0"],"?b":"b","?c":"c","?d":["aa","ee"]}
--------------------------------------------------------------------------------