継続

継続を使えるようにしました。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){

});