元の答え:
あなたの質問は、私が理解しているように、「タスクベースの非同期に特化して「待機」を実装する代わりに、call-with-current-continuation のより一般的な制御フロー操作が実装されていたらどうなるか?」です。
さて、まず「await」が何をするのか考えてみましょう。「await」は type の式を取り、Task<T>
awaiter を取得し、現在の継続で awaiter を呼び出します。
await FooAsync()
効果的になる
var task = FooAsync();
var awaiter = task.GetAwaiter();
awaiter.BeginAwait(somehow get the current continuation);
callcc
ここで、引数としてメソッドを受け取り、現在の継続でメソッドを呼び出す演算子があるとします。それは次のようになります。
var task = FooAsync();
var awaiter = task.GetAwaiter();
callcc awaiter.BeginAwait;
言い換えると:
await FooAsync()
にすぎない
callcc FooAsync().GetAwaiter().BeginAwait;
それはあなたの質問に答えていますか?
更新 #1:
コメンターが指摘しているように、以下の回答は、非同期/待機機能の「テクノロジープレビュー」バージョンからのコード生成パターンを想定しています。機能のベータ版では実際にはわずかに異なるコードを生成しますが、論理的には同じです。現在の codegen は次のようなものです。
var task = FooAsync();
var awaiter = task.GetAwaiter();
if (!awaiter.IsCompleted)
{
awaiter.OnCompleted(somehow get the current continuation);
// control now returns to the caller; when the task is complete control resumes...
}
// ... here:
result = awaiter.GetResult();
// And now the task builder for the current method is updated with the result.
これはやや複雑で、すでに計算された結果を「待っている」場合を処理することに注意してください。待機している結果が実際にメモリにキャッシュされている場合は、呼び出し元に制御を渡して中断したところから再開するという厳格な手順をすべて実行する必要はありません。
したがって、「await」と「callcc」の間の接続は、プレビュー リリースの場合ほど単純ではありませんが、基本的に awaiter の「OnCompleted」メソッドで callcc を実行していることは明らかです。必要がない場合は callcc を実行しません。
更新 #2:
この答えとして
https://stackoverflow.com/a/9826822/88656
Timwi が指摘するように、call/cc と await のセマンティクスはまったく同じではありません。「真の」call/cc では、呼び出しスタック全体を含むメソッドの継続全体を「キャプチャ」するか、同等にプログラム全体を継続渡しスタイルに書き直す必要があります。
"await" 機能は "cooperative call/cc" に似ています。継続は、「待機の時点で現在のタスクを返すメソッドが次に何をしようとしているのか」をキャプチャするだけです。タスクを返すメソッドの呼び出し元が、タスクの完了後に何か面白いことをしようとしている場合、その継続をタスクの継続として自由にサインアップできます。