6

だから私は現在、新しいプログラミング言語に取り組んでいます。並行プログラミングと Haskell から着想を得たこの言語の主な目標の 1 つは、副作用の管理です。多かれ少なかれ、各モジュールは許可する副作用を指定する必要があります。したがって、ゲームを作成する場合、グラフィック モジュールには IO を実行する機能がありません。入力モジュールには、画面に描画する機能がありません。AI モジュールは完全に純粋である必要があります。ゲームのスクリプトとプラグインは、構成ファイルを読み取るために非常に制限された IO のサブセットにアクセスできます。など。

ただし、何が副作用を構成するかは明確ではありません。このテーマについて、自分の言語で検討したい考えや提案を探しています。ここに私の現在の考えがあります。

いくつかの副作用は露骨です。ユーザーのコンソールへの出力であろうと、ミサイルの発射であろうと、ユーザーが所有するファイルの読み取りまたは書き込み、または外部ハードウェアとのやり取りを行うアクションはすべて副作用です。

他のものはより微妙で、これらは私が本当に興味を持っているものです。これらは、乱数の取得、システム時間の取得、スレッドのスリープ、ソフトウェア トランザクション メモリの実装、またはメモリの割り当てなどの非常に基本的なものなどです。

副作用を制御するために構築された他の言語 (Haskell を見てください) とは異なり、私は自分の言語を実用的で実用的なものに設計したいと考えています。副作用に対する制限は、次の 2 つの目的に役立つはずです。

  • 関心の分離を支援するため。(1 つのモジュールですべてを実行できるわけではありません)。
  • アプリケーション内の各モジュールをサンドボックス化します。(任意のモジュールをプラグインとして使用できます)

それを念頭に置いて、上で述べたように、乱数や睡眠などの「疑似」副作用をどのように処理すればよいでしょうか? 他に何を見逃したでしょうか?リソースとしてのメモリ使用量と時間をどのように管理すればよいでしょうか?

4

4 に答える 4

4

効果をどのように記述し、制御するかという問題は、現在、ハーバード大学のグレッグ・モリセットのような人々を含む、プログラミング言語の最高の科学者の一部を占めています。私の知る限り、この分野で最も野心的な先駆的な仕事は、1987年に開始されたFXプログラミング言語のDavidGiffordとPierreJouvelotによって行われました。言語の定義はオンラインですが、 1991年のPOPLペーパーを読むことで、アイデアについてより多くの洞察を得ることができます。。

于 2009-04-29T23:15:05.143 に答える
2

これは非常に興味深い質問であり、私が経験した段階の 1 つを表しており、率直に言って、それを超えました。

カール・ヒューイットが俳優の形式主義について話しているセミナーで、これについて議論したことを覚えています。彼はそれを、単に引数の関数である応答を返すメソッド、または異なる時間に異なる応答を返すメソッドの観点から定義しました。

私がこれを超えたと言ったのは、それが解決するはずの問題ではなく、言語自体 (または計算モデル) を主要な主題にするからです。これは、そのプロパティを簡単に検証できるように、言語には正式な基礎モデルが必要であるという考えに基づいています。それは問題ありませんが、より複雑なシステムは言うまでもなく、バブルソートのような単純なものの正しさを簡単に証明できる言語がまだ (私の知る限り) ないため、まだ遠い目標のままです。

上記は素晴らしい目標ですが、私が行った方向は、情報システムを情報理論の観点から見ることでした。具体的には、システムが要件のコーパス (紙または誰かの頭の中) から始まると仮定すると、それらの要件をプログラム作成マシン (自動または人間) に送信して、機能する実装のソース コードを生成できます。次に、要件に変更が発生すると、その変更は実装ソース コードへのデルタ変更として処理されます。

次に問題は、ソース コード (およびソース コードがエンコードされている言語) のどのプロパティがこのプロセスを容易にするかということです。明らかに、解決する問題の種類、どのような種類の情報が出入りするか (およびいつ)、情報を保持する必要があるか、どのような処理を行う必要があるかによって異なります。このことから、その問題に必要な言語の正式なレベルを判断できます。

コードの形式が要件に似てくるにつれて、要件の差分変更をソース コードに反映させるプロセスがより簡単になることに気付きました。表面的な類似性という観点ではなく、この類似性を測定する優れた定量的な方法がありますが、編集アクションに関して。これを最もよく表しているよく知られた技術は、ドメイン固有言語 (DSL) です。そこで、私が汎用言語に最も求めているのは、専用言語を作成できる能力だと気づきました。

アプリケーションに応じて、そのような専用言語は、関数表記法、副作用制御、並列処理などの特定の正式な機能を必要とする場合と必要としない場合があります。 、コンパイル、既存の言語での単なるマクロ、既存の言語でのクラス、変数、およびメソッドの単純な定義に至るまで。変数またはサブルーチンを宣言するとすぐに、新しい語彙が作成され、問題を解決するための新しい言語が作成されます。実際、この広い意味で、あるレベルの言語設計者でなければ、プログラミングの問題を解決できないと思います。

幸運を祈ります。新しい展望が開かれることを願っています。

于 2009-05-05T18:44:47.783 に答える
1

副作用とは、値を返す以外の世界のあらゆるものに影響を与えることです。つまり、関数の外で何らかの形で見える可能性のあるものを変更します。

純粋な関数は、関数の呼び出しの範囲外の変更可能な状態に依存したり、影響を与えたりしません。つまり、関数の出力は、定数とその入力のみに依存します。これは、関数を同じ引数で 2 回呼び出した場合、関数の記述方法に関係なく、2 回とも同じ結果が得られることが保証されることを意味します。

渡された変数を変更する関数がある場合、戻り値以外の関数からの目に見える出力であるため、その変更は副作用です。no-op ではない void 関数には、世界に影響を与える他の方法がないため、副作用が必要です。

関数は、読み取りと変更を行うその関数だけが参照できるプライベート変数を持つことができ、それを呼び出すと、将来の関数の動作が変更されるという副作用が依然としてあります。純粋であるということは、あらゆる種類の出力、つまり戻り値に対して 1 つのチャネルを持つことを意味します。

乱数を純粋に生成することは可能ですが、ランダム シードを手動で渡す必要があります。ほとんどのランダム関数は、呼び出されるたびに更新されるプライベートシード値を保持するため、毎回異なるランダムを取得できます。System.Randomを使用した Haskell スニペットは次のとおりです。

randomColor              :: StdGen -> (Color, Int, StdGen)
randomColor gen1         = (color, intensity, gen2)
 where (color, gen2)     = random gen1
       (intensity, gen3) = randomR (1, 100) gen2

ランダム関数はそれぞれ、ランダム化された値と、新しいシード (前のシードに基づく) を持つ新しいジェネレーターを返します。毎回新しい値を取得するには、新しいジェネレーター (gen1、gen2、gen3) のチェーンを渡す必要があります。暗黙的なジェネレーターは、内部変数を使用して gen1.. 値をバックグラウンドで格納するだけです。

これを手動で行うのは大変ですが、Haskell では状態モナドを使用して、はるかに簡単に行うことができます。純粋ではないものを実装するか、モナド、矢印、一意性値などの機能を使用して抽象化する必要があります。

システム時刻の取得は不正確です。時刻は尋ねるたびに異なる可能性があるためです。

スリープは関数の結果に影響を与えないため、スリープはファジーであり、常にビジー ループで実行を遅らせることができ、それは純度に影響しません。問題は、睡眠は別の目的で行われるということであり、これは副作用です。

純粋な言語でのメモリ割り当ては、暗黙のうちに行う必要があります。これは、任意の種類のポインタ比較を行うことができる場合、明示的なメモリの割り当てと解放は副作用であるためです。そうしないと、同じパラメーターで 2 つの新しいオブジェクトを作成しても、ID が異なるため (たとえば、Java の == 演算子では等しくない)、異なる値が生成されます。

私は少しとりとめのないことを知っていますが、それが副作用が何であるかを説明することを願っています.

于 2009-04-29T17:47:10.237 に答える
0

Clojureと、副作用を制御するためのソフトウェア トランザクショナル メモリ、エージェント、アトムの使用を真剣に検討してください。

于 2009-04-29T16:24:47.843 に答える