式には、 、 、 の(call/cc (lambda (k) (k 12)))3 つの継続があります。「現在の継続」はどれ?(k 12)(lambda (k) (k 12))(call/cc (lambda (k) (k 12)))
また、いくつかの本では継続は、値を待っている手続きと見なされ、値に適用されるとすぐに戻ります。そうですか?
現在の継続とは何かを詳しく説明できる人はいますか?
式には、 、 、 の(call/cc (lambda (k) (k 12)))3 つの継続があります。「現在の継続」はどれ?(k 12)(lambda (k) (k 12))(call/cc (lambda (k) (k 12)))
また、いくつかの本では継続は、値を待っている手続きと見なされ、値に適用されるとすぐに戻ります。そうですか?
現在の継続とは何かを詳しく説明できる人はいますか?
のような(k 12)ものは続きではありません。一部の大きなプログラムでは、各部分式に関連付けられた継続があります。たとえば、 in の続きxは(* 3 (+ x 42))です(lambda (_) (* 3 (+ _ 42)))。
あなたの例では、「現在の継続」は、(call/cc (lambda (k) (k 12)))その式を囲むものです。スキームプロンプトに入力しただけの場合、それを囲むものは何もないため、「現在の継続」は単に(lambda (_) _). のようなものを入力した場合(* 3 (+ (call/cc (lambda (k) (k 12))) 42))、続きは(lambda (_) (* 3 (+ _ 42))).
「現在の継続」を表すために使用したラムダは、渡されるものと同じではないことに注意してくださいcall/cc(例で名前が付けられkています)。k現在の継続を評価した後、残りの計算を中止する特別な制御効果があります。
この場合の継続は、call/cc呼び出しの戻り値を受け取る「もの」です。したがって:
(display (call/cc (lambda (k) (k 12)))
と同じ結果になります
(display 12)
Scheme の継続は、プロシージャのように「ルック アンド フィール」しますが、実際にはプロシージャのように動作しません。継続をよりよく理解するのに役立つことの 1 つは、CPS 変換です。
CPS 変換では、関数が値を返す代わりに、継続パラメーターを取り、結果で継続を呼び出します。したがって、CPS 変換さsqrtれた関数は(sqrt 64 k)、8 を返すのではなく(k 8)、末尾の位置で呼び出すだけで呼び出されます。
(CPS 変換された関数内の) 継続は末尾呼び出しであるため、関数は継続が戻ることを心配する必要がなく、実際、ほとんどの場合、継続が戻ることは期待されていません。
これを念頭に置いて、関数の簡単な例を次に示します。
(define (hypot x y)
(sqrt (+ (* x x) (* y y))))
およびその CPS 変換バージョン:
(define (hypot x y k)
(* x x (lambda (x2)
(* y y (lambda (y2)
(+ x2 y2 (lambda (sum)
(sqrt sum k))))))))
*(継続引数を受け入れるために、 、+、およびsqrtもすべて CPS 変換されていると仮定します)。
ここで、興味深い部分: CPS 変換call/ccには次の定義があります。
(define (call/cc fn k)
(fn k k))
CPS 変換により、call/cc理解しやすく、実装も簡単です。CPS 変換がなければcall/cc、非常に魔法のような実装が必要になる可能性があります (たとえば、スタック コピーなどを介して)。