2

これが「プログラム言語設計」ではなく「プログラミング」にどの程度当てはまるかは正確にはわかりません。しかし、問題はこれです:

簡単にするために、2 つの「特別な」リスト/配列/ベクトル/単に「ポート」と呼んでいるものは何でも、1 つは呼び出されstdIn、もう1 つはstdOut. これらはそれぞれ概念的に表します

  • プログラムの実行中にプログラムに与えられたすべてのユーザー入力
  • プログラムの実行中に端末に書き込まれたすべての出力

Haskell にインスパイアされた疑似コードでは、この完全に宣言的なプログラムを作成できるはずです。

 let stdOut =   ["please input a number", 
                "and please input another number", 
                "The product of both numbers is: " ++ stdIn[0] * stdIn[1]]

どちらが期待どおりで、2 つの番号を要求し、製品を印刷します。トリックは、stdOut がプログラムの完了時に端末に書き込まれた文字列のリストを表し、stdIn が入力文字列のリストを表すことです。タイプエラーと、新しい行が入力された後に次の行のみを印刷するための安全策が必要であるという事実は、簡単にするためにここでは残しておきますが、おそらくそれを解決するのは簡単です.

では、このアイデアを実装する前に、私が見落としていた落とし穴はありますか? 私は似たような構造がすでに存在していることを認識していないので、私が見落としていた明らかな落とし穴があることを考慮しないのはナイーブです.

そうでなければ、私はもちろんそれを知っています:

 let stdOut =   [stdIn[50],"Hello, World!"]

これらの結果を上記と同様の方法で織り合わせる必要がある場合は、エラーになります。

4

4 に答える 4

6

同様のアプローチが Haskell の初期のバージョンで使用されていましたが、stdin および stdout チャネルの要素が文字列ではなく、一般的な IO 'アクション' であったことを除きます。実際、入力と出力は 'response' と 'request' に一般化されていました。両方のチャネルが遅延している (つまり、実際には「反復子」または「列挙子」である) 限り、ランタイムは単純に要求チャネルをたどり、各要求を処理し、適切な応答を応答チャネルに追加できます。残念ながら、このシステムは非常に使いづらかったため、モナディック IO を支持して廃止されました。次の論文を参照してください。

  • Hudak, P. および Sundaresh, R. 純粋に機能的な I/O システムの表現力について。技術。Rep. YALEU/DCS/RR-665, Department of Computer Science, Yale University, Mar. 1989.
  • Peyton Jones, S. Tackling the Awkward Squad: Haskell でのモナディック入出力、同時実行性、例外、および外国語呼び出し。ソフトウェア構築の工学理論、2002 年、pp. 47--96。
于 2010-06-04T00:20:50.747 に答える
5

あなたが説明しているアプローチは、「ダイアログ」のように聞こえます。受賞歴のある 1993 年の論文Imperative Functional Programmingで、Phil Wadler と Simon Peyton Jones は、ダイアログが実際にはうまく機能しない例をいくつか挙げ、なぜモナディック I/O が優れているのかを説明しています。

于 2010-06-04T02:19:15.493 に答える
1

このアプローチは、I/O を純粋な λ 計算に追加する「最も明白な」方法のようであり、Haskell と Miranda でこれらの線に沿った何かが試みられたと他の人が言及しています。

ただし、λ計算に基づいていない言語で、非常によく似たシステムを使用していることを私は知っています。

副作用のない言語で入力と出力を処理する方法は? ある意味では、入力と出力は副作用ではありません。それらは、いわば、前効果と後効果です。(...) [プログラムとは] 可能な入力の空間から可能な出力の空間への関数です。

入力ストリームと出力ストリームは、それぞれが 1 バイトに対応する 0 から 255 までの自然数のリストとして表されます。ファイルの終わりは、リストの終わりではなく、値 256 で表されます。(これは、EOF を特殊なケースとして扱うよりも、文字として扱う方が簡単な場合が多いためです。それでも、end-of-list を使用した方がよいのではないかと思います。)

(...)

対話型プログラムを作成することは難しくありません (...) [しかし] 技術的に言えば、そうすることは罪です。(...) 参照が透過的な言語では、明示的に同期されていないものはすべて、ランタイム システムの裁量で、任意の順序で評価されます。

(...) この特定のプログラムを作成する最も明白な方法は、"Hello, [name]!" をコンスすることです。改行の受信を条件とする式の文字列。これを行うと、ユーザーが改行を入力することを評価者が事前に証明する方法がないため、安全です。

(...)

したがって、対話型ソフトウェアには実用上の問題はありません。それにもかかわらず、2 番目のケースが防止される方法については、何か不快な点があります。参照透過的なプログラムは、適切に動作するために遅延評価に依存する必要はありません。

この道徳的ジレンマから逃れるには?困難な方法は、入力と出力が明示的に同期される、おそらく Haskell に基づく、より洗練された I/O システムに切り替えることです。私は現在のシステムのシンプルさを好むので、これを行うのはかなり気が進まない. 簡単な方法は、たまたま対話的にうまく動作するバッチ プログラムを作成することです。これは主に、ユーザーにプロンプ​​トを表示しないという問題です。

おそらく、 Lazy Kでプログラミングを楽しんでいただけますか?

于 2010-06-04T14:03:54.747 に答える
1

あなた自身の例と比較して、この例を考慮してそれらをどのように織り込むかわかりません:

let stdOut =   ["Welcome to the program which multiplies.",
                "please input a number", 
                "and please input another number", 
                "The product of both numbers is: " ++ stdIn[0] * stdIn[1]]

stdIn[0]プログラムは、 1 行 (例のように) または 2 行を出力した後、 で表される番号を要求する必要がありますか? インデックス0が stdin からの 0 番目の入力を表す場合、次のようになります。

let stdOut =   ["Welcome to the program which multiplies.",
                "please input a number",
                some_annotation(stdIn[0]),
                "and please input another number", 
                some_annotation(stdIn[1]),
                "The product of both numbers is: " ++ stdIn[0] * stdIn[1]]

出力と入力のタイミングを調整するために必要になります。

私はあなたの考えが好きです。some_annotationあなたの好みに置き換えてください。おそらく「同期?」に似たものです。とっさの言葉が思いつきませんでした。

于 2010-06-04T02:27:40.363 に答える