r6rsスキームレポート を読んでいて、継続の説明に混乱しています(密度が高すぎて、初心者には例が不足していることがわかります)。
このコードは何をしていて、どのように4に評価されますか? call/cc
が1つの引数の関数である引数を必要とするのはなぜですか? call/cc
の引数はどのように使用されますか?
(+ 1 (call-with-current-continuation
(lambda (escape)
(+ 2 (escape 3)))))
=⇒ 4
この例はセクション1.11-継続からのものです。
call/cc
は、1つの引数を持つ関数を取ります。これは、その引数に「現在の継続」が入力されるためです。この場合の継続は、call/cc
の「直後」のポイント、つまり戻り値が設定されているポイントに戻ります。
したがって、(escape 3)
を呼び出すと、式の残りの部分((+ 2 ...)
)は破棄され、call/cc
の戻り値として3が設定されます。したがって、(+ 1 (call/cc ...))
は(+ 1 3)
として評価されるため、結果は4になります。
クリスの答えは素晴らしいですが、私はそれを理解したので、初心者の観点から継続にもう少し説明を追加したいと思います。
(define call/cc call-with-current-continuation)
を実行し、hop
(「TheSeasonedSchemer」の方法で)を使用して継続を表します。
パラメータを無視する:通常の評価
(call/cc
(lambda (hop)
(+ 2 3)))
=> 5
式全体をホッピングする:通常の評価も
(call/cc
(lambda (hop)
(hop (+ 2 3))))
=> 5
オペレーターのホッピング:
(call/cc
(lambda (hop)
((hop +) 2 3))))
=> #<procedure:+>
オペランドのホッピング:
(call/cc
(lambda (hop)
(+ 2 (hop 3))))
=> 3
ホッパーをホッピングする:
(call/cc
(lambda (hop)
(hop hop)))
=> #<continuation>
基本的に、call/cc
を使用すると、式から「ホップ」して、指定された戻り値で計算をすぐに中止する方法が得られます。
call/cc
を使用するためのより洗練された方法はたくさんありますが、私にはわかりませんが、OPとは関係ありません。
多くの例を含むこの紹介 継続を理解するのに役立ちました。
とにかく。これらは、継続を(乱用)使用する方法のいくつかの例です。
(define (pair-up x)
(call/cc (lambda (continuation)
;; recursive helper functions
(define (pair-up-aux x)
(if (null? x)
'()
(if (null? (cdr x))
(continuation #f) ; cancel everything and return #f
(cons (cons (car x) (cadr x)) (pair-up-aux (cddr x)))))) ; build result
(pair-up-aux x))))
このコードはリストを取り、(pair-up '(a b c d))が((a .b)(c .d))になるようなペアのリストを作成します。それは、consesを繰り返して連鎖させることによってそうします。リストの最後にいて、最後のペアを作成するための要素が1つ不足していることがわかったら、すべてをキャンセルして、代わりに#fを返します。 (pair-up '(a b c))を実行し、#fを返した場合、((a .b)。#f)を取得します。現時点でのcall/ccは、私が自分のリターンを構築し始めたとしても、私の考えを変えて、何か他のものを一緒に返す機会を与えてくれます。 (継続#f)は、call/ccが関数本体の周囲にあるため、このプロシージャの結果として#fを返します。次の例では、継続を伴うループを実装します。
(let ((x 0))
(let ((cont (call/cc (lambda (x) (x x)))))
(set! x (+ x 1))
(display x)
(newline)
(if (= x 10)
(display "Finished!\n")
(cont cont))))
これで実際に1..10が出力され、継続を呼び出すと、letの本体が数回実行されます。 2つの別々のlet(またはlet *)を使用する必要がありました。そうしないと、xは各実行時に初期化され、xが10になることはありません。