コルーチンと継続とジェネレータの違いは何ですか?
ベストアンサー1
最も単純なケースであるジェネレータから始めます。@zvolkov が述べたように、ジェネレータは、返さずに繰り返し呼び出すことができる関数/オブジェクトですが、呼び出されると値を返し (yield)、その後実行を一時停止します。ジェネレータが再度呼び出されると、最後に実行を一時停止した場所から開始し、再び処理を実行します。
ジェネレーターは、本質的には縮小された(非対称の)コルーチンです。コルーチンとジェネレーターの違いは、コルーチンは最初に呼び出された後に引数を受け入れることができるのに対し、ジェネレーターはそれができないことです。
コルーチンを使用する簡単な例を挙げるのは少し難しいですが、ここで私の最善の試みを示します。例として、この (架空の) Python コードを見てみましょう。
def my_coroutine_body(*args):
while True:
# Do some funky stuff
*args = yield value_im_returning
# Do some more funky stuff
my_coro = make_coroutine(my_coroutine_body)
x = 0
while True:
# The coroutine does some funky stuff to x, and returns a new value.
x = my_coro(x)
print x
コルーチンが使用される例としては、字句解析器とパーサーがあります。言語にコルーチンがない場合、または何らかの方法でエミュレートされていない場合、字句解析コードとパーシング コードは実際には別々の問題であるにもかかわらず、混在させる必要があります。しかし、コルーチンを使用すると、字句解析コードとパーシング コードを分離できます。
(対称コルーチンと非対称コルーチンの違いについては簡単に説明します。簡単に言えば、これらは同等であり、一方から他方に変換でき、ジェネレーターに最も似ている非対称コルーチンの方が理解しやすいということです。ここでは、Python で非対称コルーチンを実装する方法を概説しました。)
継続は実は非常に単純なものです。継続とは、プログラム内の別のポイントを表す関数であり、これを呼び出すと、実行は自動的にその関数が表すポイントに切り替わります。継続の非常に制限されたバージョンを、毎日、気づかないうちに使用しています。たとえば、例外は、裏返しの継続の一種と考えることができます。継続の Python ベースの疑似コード例を示します。
Python に という関数がありcallcc()
、この関数が 2 つの引数を取り、最初の引数が関数で、2 番目の引数が関数を呼び出すための引数のリストであるとします。この関数の唯一の制約は、受け取る最後の引数が関数 (現在の継続) になることです。
def foo(x, y, cc):
cc(max(x, y))
biggest = callcc(foo, [23, 42])
print biggest
すると、 は現在の継続 ( )、つまり が呼び出されたプログラム内のポイントへの参照を使用して をcallcc()
呼び出します。が現在の継続を呼び出す場合、それは基本的に、現在の継続を呼び出す値を使用して を返すように指示するのと同じであり、その場合、 はスタックを現在の継続が作成された場所、つまり を呼び出した時点までロールバックします。foo()
cc
callcc()
foo()
callcc()
callcc()
このすべての結果として、仮想の Python バリアントは を出力します'42'
。