継続
継続を使えるようにしました。svn上のプログラムを落とせば使えます。
継続は current_continuation で取得します。current_continuation は 継続オブジェクトとユーザーが渡した値の二つの値を返します。継続オブジェクトを関数呼び出しすれば、current_continuationのところまで復帰します。
cc, value: current_continuation; // valueは最初nullを返す。 if(!value){ value = 0; } if(value<5) cc(value+1); //=>0 //=>1 //=>2 //=>3 //=>4 //=>5
さて、Rubyのブロックに出来てXtalのブロックに出来ないこととして、次のような「関数登録として使う」というのがあります。
$events = [] def add_event(&block) $events.push(block) end add_event{ puts "a" }
Xtalではfor文に展開されるだけで、ブロックを関数に渡しているわけではないので、これは不可能でした。
ところが、今回追加された継続を使えばこれも可能となります。
Callback: class{ @cc: null; @back: null; iter_first: method(){ nx: null; @cc, nx = current_continuation; if(!nx){ return null; } return this; } iter_next: method(){ @back(true); } iter_break: method(){ @back(true); } op_call: method(){ nx: null; @back, nx = current_continuation; if(!nx){ @cc(true); } } } CallbackManager: class{ @list: []; append: method(){ c: Callback(); @list.push_back(c); return c; } op_call: method(){ @list.each{ it(); } } } cm: CallbackManager(); cm.append{ "a".p; } cm.append{ "b".p; } cm.append{ "c".p; } cm.append{ "d".p; } cm();
Schemeのcallccのような形の関数は次のように定義できます。
callcc: fun(fn){ first: true; cc, nx: current_continuation; if(first){ first = false; return fn(cc); } return nx; } callcc(fun(cc){ });