したがって、データベースのクエリやファイルの書き込みは、純粋に機能的なスタイルで行うことはできません。たとえば、モナドが必要な理由の1つです。
モナドを「必要とする」人はいません。それは物事を説明する1つの方法にすぎません。実際、それはおそらく最善の方法でもありません。何らかの効果の型付け、一意性の型、または完全線形論理に基づくシステムは、理論上は説得力があるように見えますが、よく知られている型システムからの根本的な逸脱であり、表現するのがより複雑です。Haskellに見られるモナディックIOは、言語で既に使用されている既存のMLスタイルの型システムと簡単に共存できる方法で完全に命令型プログラミングを本質的にモデル化するため、使いやすさとシンプルさの妥協点です。
問題は、なぜSTDOUT出力を不純なものと見なすのかです。はい、どんなファイルハンドラーも危険です-データが常に書き込まれると確信することはできません。しかし、STDOUTはどうですか?なぜそれを信頼できないものと考えるべきなのでしょうか?評価自体の方が信頼性が低いですか?つまり、トリガーを引いて、計算を中断することができます。
そうではありません。プログラム全体への入力およびプログラム全体からの出力は、単に引数と見なすことができ、プログラム全体を1つの大きな純粋な関数として扱った結果です。stdinから同じものをフィードした場合、同じものをstdoutに出力する限り、それは純粋な関数です。実際、モナディックIOを導入する前に、Haskellは入出力に純粋な遅延ストリームを使用するストリームベースのI / Oシステムを使用していました。それは明らかに使用するのが苦痛だったのでそれを落としました、それはなぜあなたがこのような何かを聞いたことがないのかについてあなたにいくつかの考えを与えるかもしれません。:]
馬鹿げた方法で要点を述べるために、ミニマリストの難解な言語であるレイジーKを考えてみましょう。
レイジーKは、ガベージコレクションされた参照透過的な関数型プログラミング言語であり、シンプルなストリームベースのI / Oシステムを備えています。
Lazy Kを他のそのような言語と区別するのは、他の機能がほとんどないことです。たとえば、統合されたHindley-Milner多態型システムは提供されません。プラットフォームに依存しないGUIプログラミングと他の言語へのバインディングをサポートする広範な標準ライブラリは付属していません。特に、Lazy Kは組み込み以外の関数を定義または参照する方法を提供していないため、このようなライブラリを作成することもできません。この機能がないことは、数値、文字列、またはその他のデータ型のサポートが対応していないことによって補完されます。それにもかかわらず、Lazy Kはチューリング完全です。
(...)
レイジーKプログラムは、数学関数と同じ時代を超越したプラトニックの領域に住んでいます。ガベージコレクションがメモリ管理のプロセスをプログラマから隠すのと同じように、参照の透過性は評価のプロセスを隠します。マンデルブロ集合の画像を表示するために、またはレイジーKプログラムを「実行」するために、いくつかの計算が必要であるという事実は、実装の詳細です。それが関数型プログラミングの本質です。
(...)
副作用のない言語で入力と出力を処理する方法は?ある意味では、入力と出力は副作用ではありません。それらは、いわば、フロントエフェクトとバックエフェクトです。したがって、それはLazy Kにあり、プログラムは可能な入力の空間から可能な出力の空間への関数として単純に扱われます。
それよりも純粋な関数型言語が見つかるとは思えません!
ただし、上記は本質的に純粋な関数の入力と出力を受け取り、それらを何らかの方法で「外部」でstdin / stdoutに接続する場合にのみ適用されることに注意してください。それと実際のシステムレベルのI / Oプリミティブへのアクセスとの間には大きな違いがあります。ストリームへの読み書きの実装の詳細は、慎重にカプセル化しない限り、不純物をリークする可能性があります。
これがHaskellで直接これを行うことができない主な理由だと思います-賢明なユースケースはモナディックIOを使用する場合に比べてスリムであり、後者の場合、本物にアクセスできることには多くの利点があります。たとえば、プログラムへのコマンドライン引数は、main
直感的にはそうであるように見えても、単純に引数としてに渡されないのはそのためだと思います。
ただし、特定のプログラムでこのような最小バージョンを回復することはできます。引数を純粋な値としてキャプチャし、プログラムの残りの部分で関数を使用するinteract
だけです。