2008-01-20
■ [biwascheme] クロージャを実行するような関数をjsレベルで定義できるようにした(2)
JavaScriptで書けるっていうけど、必ずCPS形式で書かんといかんよね?それはもうSchemeで書いた方が楽では?w
と書いたのだが、よく考えるとリストやベクタの各要素について一度ずつ繰り返すものばっかりなので、 そういうループをCPS化したものを用意し、コールバックでカスタマイズできるようにしてみた。
mapがこんな風に書ける。
define_libfunc("map", 2, null, function(ar){ //TODO: multi lists support var proc = ar[0], ls = ar[1]; assert_pair(ls); var a = []; return Call.foreach(ls, { call: function(x){ return new Call(proc, [x]) }, result: function(res){ a.push(res); }, finish: function(){ return a.to_list(); } }) })
remp (Rubyでいうreject) はこんな風に書ける。
define_libfunc("remp", 2, 2, function(ar){ var proc = ar[0], ls = ar[1]; assert_pair(ls); var ret = []; return Call.foreach(ls, { call: function(x){ return new Call(proc, [x]) }, result: function(res, x){ if(!res) ret.push(x); }, finish: function(){ return ret.to_list(); } }) })
実装
Call.foreachは昨日書いたCallのラッパーで、以下のような定義になっている。Iteratorは自分で書いた外部イテレータで、配列、文字列、リストに対応している。
WebScheme.Call.foreach = function(obj, callbacks){ var iterator = null; var x = null; var loop = function(ar){ if(iterator) callbacks["result"](ar[0], x); else iterator = Iterator.of(obj); if(!iterator.has_next()) return callbacks["finish"](); else{ x = iterator.next(); var result = callbacks["call"](x); result.after = loop; return result; } } return loop(null); }
クロージャ呼び出しの前後で分断されるので、loopはリストの長さより1回多く実行されることに注意。例えば3要素のリストに対して繰り返す場合、
loop 1 : call loop 2 : result call loop 3 : result call loop 4 : result finish
のように、4回loop関数が実行される。
さて、あとは、もうちょっと良いコールバック名を考えるべきか(^^;
■ [biwascheme] ネットワークからソースを読み込む機能を実装した
ネットワークから別のソースを取ってきて実行する機能を実装しました。
(load "plapla.scm") (plapla "hitode909")
例。REPLで上のソースを実行すると、サーバ上に置かれたplapla.scmの内容がロードされて、
"hitode909++"
という結果になります。:-)
plapla.scmの中身が見たい場合は
(display (http-request "plapla.scm"))
など。