5

継続は、次に何が起こるかを何らかの値で表しますよね?それは、値を取り、何らかの計算を行う単なる関数ではありませんか?

(+ (* 2 3) 5)

の続き(* 2 3)(+ _ 5)

(define k (lambda (v) (+ v 5)))

call/cc関数を使用せずにここで使用するポイントは何kですか?

4

3 に答える 3

6

真実。すべてのプログラムには、停止するまで継続があります。通常、1 つの継続は、基礎となる実装によって行われる計算の 1 つのステップです。

あなたの例:

(+ (* 2 3) 5)

組み合わせ + は、最初に終了する組み合わせ * に依存します。したがって(+ result 5)、確かに の続きです(* 2 3)。ただし、このコンテキストでは手順ではありません。の有用性はcall/cc、後悔して代わりに別のことをしたい、または後でこれに戻りたいという続きがある場合です。最初にやりましょう:

(define g 0)
(call/cc 
  (lambda (exit)
    (/ 10 (if (= g 0) (exit +Inf.0) g))))

明らかに、if の結果が実行されたときに継続する除算がありますが、exit実行されているため、全体が短絡して +Inf.0 が返されます。

後で除算を行わせずに、手順でそれを行うにはどうすればよいでしょうか? このスタイルでは、できません。

Scheme はコードをContinuation Passing Style(=CPS)に変換し、CPS では call/cc は特別なものではないため、これは魔法ではありません。CPS でコードを書くのは簡単ではありません。

これがCPSの定義ですcall/cc

(define (kcall/cc k consumer)
  (consumer k (lambda (ignore v) (k v))))
于 2013-08-29T23:57:14.437 に答える
4

おめでとう!あなたは継続渡しスタイルを発明しました! あなたが行ったこととの唯一の違いcall/ccは、call/ccそれが自動的に行われ、コードを再構築する必要がないことです。

于 2013-08-30T20:54:50.610 に答える
2

「継続」とは、計算の未来全体です。計算のすべてのポイントには継続があり、単純に言えば、現在のプログラム カウンターおよび現在のスタックと考えることができます。Schemecall/cc関数は、現在の構成を便利にキャプチャし、それを関数にパッケージ化します。その関数を呼び出すと、計算のその時点に戻ります。したがって、継続は関数とは大きく異なります (ただし、継続関数は関数です)。

call/cc通常適用される2 つの一般的なケースがあります。

  1. 非ローカル出口。継続を確立し、何らかの計算を行い、継続を呼び出した計算を突然終了します。

  2. 計算を再開/再入力します。この場合、継続を保存してから、必要に応じて再度呼び出します。

ケース #1 の例を次に示します。

(begin
  ;; do stuff
  (call/cc (lambda (k)
              ;; do more

             ;; oops, must 'abort'
             (k 'ignore)))
  ;; continue on
  )

ケース #2 の例を次に示します。

> (define c #f)
> (let ((x 10))
   (display (list (+ 1 (call/cc (lambda (k) (set! c k) x))) 111))
   (display " more"))
(11 111) more
> (c 20)
(21 111) more
> (c 90)
(91 111) more

このケース #2 では、継続によって最上位の read-eval-print ループに戻ることに注意してください。これにより、この例で継続を再度呼び出すことができます。

于 2013-08-30T22:24:24.067 に答える