7

これは、 call / ccとは何ですか?に関連しています。、しかし私は自分の目的のためにこの質問をハイジャックしたくありませんでした、そしてsetjmp/longjmpへのアナロジーのようなその議論のいくつかは私を回避します。

継続とは何かについては十分に理解していると思います。これは、現在の呼び出しスタックのスナップショットだと思います。なぜこれが面白いのか、継続で何ができるのかについては議論したくありません。私の質問は、より具体的には、なぜcall / ccに関数の引数を提供する必要があるのですか?なぜcall/ccは現在の継続を返さないので、私はそれで好きなことを何でもすることができます(それを保存し、それを呼び出し、あなたはそれに名前を付けます)?この他の質問(http://community.schemewiki.org/?call-with-current-continuation-for-C-programmers)からのリンクでは、「本質的に、それはあなたに継続を取得するためのクリーンな方法です。そして、保存されたポイントに戻る後続のジャンプの邪魔にならないようにしてください。」しかし、私はそれを取得していません。不必要に複雑に見えます。

4

4 に答える 4

9

Jay が示すような構造を使用すると、継続を取得できますが、ある意味では、取得された値は既にその継続の中にいるため、既に損なわれています。対照的に、現在の式の外でまだ保留中call/ccの継続を取得するために使用できます。たとえば、継続の最も単純な使用法の 1 つは、一種の an を実装することです。abort

(call/cc (lambda (abort)
           (+ 1 2 (abort 9))))

あなたが説明した操作ではそれを行うことはできません。試してみると:

(define (get-cc) (call/cc values))
(let ([abort (get-cc)]) (+ 1 2 (abort 9)))

9次に、プロシージャとして適用することに関するエラーが発生します。これは、 が --という新しい値で にabort戻るために発生します。これは、同じ加算式の 2 回目のラウンドを実行していることを意味します。let9abort9

2 つの追加の関連メモ:

  1. 継続の実用的な紹介については、PLAIを参照してください。
  2. call/cc 、関数を受け取るという点で少し複雑です。概念的に使いやすい構造はlet/cc、PLT スキームなどの一部の実装で見つけることができます。上記の例は となり(let/cc abort (+ 1 2 (abort 9)))ます。
于 2009-07-14T03:45:09.530 に答える
2

それは汎用性が低いでしょう。その動作が必要な場合は、次のようにするだけです。

(call/cc (lambda (x) x))

「Darrell Ferguson and Dwight Deugo. "Call with Current Continuation Patterns". 8th Conference on Pattern Languages of Programs. September 2001.」で継続の使用例を見ることができます。( http://library.readscheme.org/page6.html ) 上記のように定義された call/cc-return を使用してそれらを書き換えてみてください。

于 2009-07-13T14:57:33.513 に答える
2

自問することから始めることをお勧めします: ファーストクラスの継続とはどういう意味ですか?

式の継続は、基本的に 2 つのデータから構成されます。2 つ目は、式の結果に対して何を行うべきかの表現です。したがって、ファーストクラスの継続を持つ言語は、これらの部分をカプセル化するデータ構造を持ち、これらのデータ構造を他のものと同じように扱う言語です。

call/cc は、このアイデアを実現するための特に洗練された方法です。現在の継続は、式に適用されたときにプロシージャが行うこととして、式で行われることをカプセル化するプロシージャとしてパッケージ化されています。このように継続を表すということは、単に、このプロシージャーのクロージャーに、呼び出されたサイトの環境が含まれていることを意味します。

他の方法でファーストクラスの継続のアイデアを実現することを想像することができます. それらは call/cc ではありません。そのような表現がどのように単純になるか想像するのは難しいです。

別れのメモとして、Eli が言及した let/cc の実装について考えてみましょう。私はこれを bind/cc と呼びます。

(define-syntax bind/cc
    (syntax-rules ()
        ((bind/cc var . body)
             (call/cc (lambda (var) . body)))))

演習として、bind/cc に基づいて call/cc をどのように実装しますか?

于 2009-12-04T19:39:25.050 に答える
2

一般的な SO ネチケットに対して、私は自分自身の質問に答えていますが、回答の提供者というよりは編集者としての役割を果たしています。

しばらくして、LtUで同様の質問を始めました。結局のところ、これらは一日中言語設計について熟考している連中ですよね。そして、その答えの 1 つがついに私に与えられました。ここで言及されていること、たとえばEliや元の質問で言及されていることは、私にとってはるかに理にかなっています. 何が継続に含まれるか、適用された継続がどこに設定されるかがすべてです。

LtUのポスターの 1 つは次のように書いています。

「call/cc を使用すると、どのように「邪魔にならないようにする」ことができるかを正確に確認できます。em または get/cc を使用すると、何らかのテストを行って、バックジャンプがあるのか​​、それとも最初の呼び出しだけなのかを判断する必要があります。基本的には、 、 call/cc は継続の使用を継続の外に保ちますが、 get/cc または em では、継続にはその使用が含まれているため、(通常) 継続の先頭にテストを追加する必要があります (つまり、 get の直後) /cc / em) を使用して、「継続部分の使用」を「継続の残り」部分から分離します。

それは私にとって家に帰りました。

とにかくありがとう!

于 2009-12-07T22:30:30.833 に答える