ファーストクラスの継続は、最新のオブジェクト指向プログラミング言語で役立ちますか?


10

継続はCont、命令型コードの単純で規則的な表記を可能にするため、関数型プログラミング言語(Haskell のモナドなど)では非常に便利です。また、欠落している言語機能(例外、コルーチン、グリーンスレッドなど)の実装に使用できるため、一部の古い命令型言語でも役立ちます。しかし、これらの機能のために建てられたサポート付きのモダンなオブジェクト指向言語のためにも(かどうか、より現代的なスタイル区切られたファーストクラスの継続のためのサポートを追加するためにどのような引数があるだろうresetshiftか、スキームのようなcall-with-current-continuation)?

パフォーマンスと実装の複雑さ以外のサポート追加することに反対する議論はありますか?

回答:


15

Eric Lippertにこれに答えさせましょう。

この時点で明らかな問題は、CPSが非常に優れている場合は、なぜそれをいつも使用しないのかということです。ほとんどのプロの開発者がそれを聞いたことがないのか、あるいは、それを知っている人が、クレイジーなSchemeプログラマーだけが行うことと考えているのですか?

まず第一に、サブルーチン、ループ、try-catch-finallyなどについて考えることに慣れているほとんどの人にとって、デリゲートがこのように制御フローに使用されていることを推論することは簡単ではありません。私は今、CS442からのCPSに関するメモを確認しています。1995年にprofQUOTEを書き留めたことがわかりました。「継続する場合は、頭の上に立って、裏返しにする必要があります」。ダガン教授(*)はそれを言っているのは絶対に正しかった。数日前から、C#式M(B()?C():D())のCPS変換の小さな例に4つのラムダが含まれていたことを思い出してください。誰もが高階関数を使用するコードを読むのが得意ではありません。それは大きな認知的負担を課します。

さらに、特定の制御フローステートメントを言語に焼き付けることの優れた点の1つは、メカニズムによって、呼び出しスタック、戻りアドレス、例外ハンドラーリスト、保護された領域を隠しながら、コードで制御フローの意味を明確に表現できることです。等々。継続により、制御フローのメカニズムがコードの構造で明示的になります。メカニズムに重点を置くと、コードの意味がわかりにくくなります。

では次の記事、彼は非同期かつ継続は互いにまったく同じであるかを説明し、簡単なを取ってのデモンストレーションを乗り越え、(しかし、ブロッキング、)同期ネットワークの運用とasyncronousスタイルでそれを書き換え、必ずすべての隠さをカバーすることそれを正しくするためにカバーする必要がある落とし穴。それは巨大なコードの混乱に変わります。最後の彼の要約:

神聖な善、私たちが作ったなんてひどい混乱です。完全に明確な2行のコードを、これまでにない最もゴージャスなスパゲッティの20行に拡張しました。そしてもちろん、ラベルがスコープ内になく、割り当てエラーがあるため、コンパイルもできません。これらの問題を修正するには、コードをさらに書き直す必要があります。

CPSの長所と短所について私が言っていたことを覚えていますか?

  • PRO:単純なパーツから任意に複雑で興味深い制御フローを構築できます–チェックしてください。
  • CON:継続による制御フローの具体化は、読みにくく、推論も難しい–チェック。
  • CON:制御フローのメカニズムを表すコードは、コードの意味を完全に覆します–チェック。
  • CON:通常のコード制御フローからCPSへの変換は、コンパイラーが得意で、他の誰も得意としないものです–チェックしてください。

これは知的運動ではありません。実際の人々は、非同期性を扱うとき、常に上記と道徳的に同等のコードを書くことになります。そして皮肉なことに、プロセッサーがより速く、より安価になったとしても、プロセッサーに縛られないものを待つために私たちはますます多くの時間を費やしています。多くのプログラムで、費やされる時間の多くは、ネットワークパケットがイギリスから日本に移動して再び戻るのを待つか、ディスクがスピンするか、その他を待つためにプロセッサがゼロに固定されています。

さらに、非同期操作をさらに構成したい場合に何が起こるかについても触れていません。ArchiveDocumentsをデリゲートをとる非同期操作にしたいとします。これを呼び出すすべてのコードもCPSで記述する必要があります。汚れが広がるだけです。

非同期論理権を取得することで重要なのは、それだけになるだろう 将来的にはもっと重要な、と私たちは与えられたツールはあなたが作る 「あなたの頭の上に立って、裏返しに自分自身を回す」として教授ダガンは賢明に言いました。

はい、継続渡しのスタイルは強力ですが、その力を上手く利用するには、上記のコードよりも優れた方法が必要です。

両方の記事、およびこのすべての混乱をコンパイラーに移動し、特定の部分を非同期としてマークする特別なキーワードを使用して通常の制御フローとしてコードを記述できるようにする新しいC#言語機能に関する次のシリーズは、読者が読んでも価値があるC#開発者ではありません。私はそうではありませんが、初めてそれに遭遇したときは、それでもまだ非常に啓発的な経験でした。


5
お使いの言語がマクロのような構文拡張をサポートしている場合、構文拡張内にさまざまな種類の興味深い制御フローを実装するためのメカニズムを隠すことができるため、継続ははるかに便利になります。これは基本的に「待機」の動作方法です。C#はこのような種類の構文拡張を自分で定義するツールを提供していないため、言語で定義されているだけです。
ジャック

良い記事ですが、CPSとファーストクラスの継続はまったく同じではないことに注意します(CPSは、継続が必要であるとわかったときに、継続をサポートしない言語で行うものです)。C#は私が考えているのとまったく同じルートを進んでいるようです(ただし、タイヤのCPSへの変換を自動化するか、本格的なスタックコピー区切りの継続を実装するかを決定することはできません)。
ジュール

@ジャック-それはまさに私が今検討していることです。私が設計している言語には、CPS変換を自動的にサポートできるマクロ機能があります。しかし、完全なネイティブの継続によりパフォーマンスが向上する可能性があります...問題は、パフォーマンスがクリティカルな状況でどれだけ頻繁に使用されるかということです。
ジュール、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.