式には、 、 、 の(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
、非常に魔法のような実装が必要になる可能性があります (たとえば、スタック コピーなどを介して)。