不変性または可変性は、関数型プログラミングで意味のある概念ではありません。
計算コンテキスト
これは非常に良い質問であり、最近の別の質問に対する興味深いフォローアップです(重複ではありません)。割り当て、評価、および名前バインディングの違いは何ですか?
ここでは、あなたの発言に1つずつ返信するのではなく、問題となっていることの構造化された概要を説明します。
あなたに答えるために考慮すべきいくつかの問題があります。
関数型プログラミングスタイルは、プログラマーの命令型の目で見るとばかげているように見えます。しかし、それは別のパラダイムであり、あなたの命令的な概念と知覚は場違いです。コンパイラーにはそのような偏見はありません。
しかし、最終的な結論は、機械学習を含む純粋に関数的な方法でプログラムを作成することが可能であり、関数型プログラミングにはデータを格納するという概念がないと考えたということです。この点については他の回答とは意見が一致しないようです。
この回答の長さにもかかわらず、少数の人が興味を示すことを期待しています。
計算パラダイム
問題は、計算の特定のモデルである関数型プログラミング(別名アプリケーションプログラミング)に関するもので、その理論的で最も単純な代表はラムダ計算です。
理論レベルに留まる場合、チューリングマシン(TM)、RAMマシンなど、ラムダ計算、組み合わせロジック、再帰関数理論、セミチューシステムなど、多くの計算モデルがあります。より強力な計算モデルは対応できる点で同等であることが証明されており、それがChurch-Turing論文の要点です
。
重要な概念は、モデルを互いに縮小することです。これは、チャーチチューリングの論文につながる同等性を確立するための基礎です。プログラマーの観点から見ると、1つのモデルを別のモデルに縮小することは、通常コンパイラーと呼ばれるものです。計算のモデルとして論理プログラミングを採用すると、店舗で購入したPCが提供するモデルとはかなり異なり、コンパイラは論理プログラミング言語で記述されたプログラムをPCが表す計算モデルに変換します(かなり多くの場合)。 RAMコンピュータ)。
β
実際には、私たちが使用するプログラミング言語は、理論的に異なる起源の概念を混合する傾向があり、プログラムの選択された部分が適切な場所にあるモデルのプロパティから利益を得ることができるようにしています。同様に、システムを構築する人々は、現在のタスクに言語を最適に合わせるために、異なるコンポーネントに異なる言語を選択する場合があります。
したがって、プログラミング言語の純粋な状態のプログラミングパラダイムはめったにありません。プログラミング言語は依然として主要なパラダイムに従って分類されていますが、他のパラダイムからの概念が含まれる場合、言語の特性が影響を受け、区別や概念的な問題が不明瞭になることがよくあります。
通常、HaskellやMLまたはCAMLなどの言語は関数型と見なされますが、命令型の動作を可能にすることができます...さもなければ、なぜ「純粋に関数型のサブセット」と言えるのでしょうか。
次に、これまたは私の関数型プログラミング言語でそれを行うことができると主張できますが、それは、関数型プログラミングに関する質問に実際に答えているわけではありません。
答えは、余分なものなしで、より正確に特定のパラダイムに関連している必要があります。
変数とは何ですか?
もう1つの問題は、用語の使用です。数学では、変数は、あるドメインで未決定の値を表すエンティティです。さまざまな目的で使用されます。方程式で使用される場合、方程式が検証されるような任意の値を表す場合があります。このビジョンは、「論理変数」という名前で論理プログラミングに使用されています。おそらく、変数の名前は、論理プログラミングの開発時にすでに別の意味を持っていたためです。
従来の命令型プログラミングでは、変数は値の表現を記憶し、場合によっては現在の値を別の値に置き換えることができるある種のコンテナー(またはメモリロケーション)として理解されます。
関数型プログラミングでは、変数は、数学では同じ値を、まだ提供されていない値のプレースホルダーとして使用します。従来の命令型プログラミングでは、この役割は実際には定数によって行われます(123、true、["abdcz"、3.14]などの値のドメインに固有の表記で表現された値を決定するリテラルと混同しないでください)。
定数だけでなく、あらゆる種類の変数は識別子で表すことができます。
命令型変数はその値を変更することができ、それが可変性の基礎となります。関数変数はできません。
プログラミング言語では通常、言語の小さいエンティティから大きいエンティティを構築できます。
命令型言語では、このような構成要素に変数を含めることができます。これにより、可変データが提供されます。
プログラムの読み方
プログラムは基本的に、実用的な設計であろうと、パラダイム的に純粋な言語であろうと、アルゴリズムが何らかの言語であるという抽象的な説明です。
原則として、抽象的に意味することが想定されているすべてのステートメントを使用できます。その後、コンパイラーはそれをコンピューターが実行する適切な形式に変換しますが、それは最初の近似では問題ではありません。
もちろん、現実は少し厳しく、コンパイラが効率的な実行のために対処する方法を知らない構造を回避するために、何が起こるかについてある程度の考えを持つことはしばしば良いことです。しかし、それはすでに最適化です...コンパイラーは非常に良い場合があり、多くの場合、プログラマーよりも優れています。
関数型プログラミングと可変性
変更可能性は、代入によって変更される、値を含むことができる命令型変数の存在に基づいています。これらは関数型プログラミングには存在しないため、すべてが不変であると見なすことができます。
機能プログラミングは、値のみを扱います。
不変性に関する最初の4つのステートメントはほとんどが正しいですが、必須ではない何かを必須のビューで説明します。それは、すべての人が盲目である世界で色で説明するようなものです。関数型プログラミングとは異なる概念を使用しています。
純粋な値のみがあり、整数の配列は純粋な値です。1つの要素のみが異なる別の配列を取得するには、別の配列値を使用する必要があります。要素の変更は、このコンテキストには存在しない概念にすぎません。配列といくつかのインデックスを引数として持つ関数があり、ほとんど同じ配列である結果を返す場合があります。この配列は、インデックスによって示される場所のみが異なります。しかし、それはまだ独立した配列値です。これらの値がどのように表されるかは問題ではありません。多分彼らはコンピュータの命令的な翻訳で多くの「共有」をします...しかし、それはコンパイラの仕事です...そしてあなたはそれがどのような種類の機械アーキテクチャをコンパイルしているかさえ知りたくありません。
値をコピーしません(意味がありません。それはエイリアンの概念です)。プログラムで定義したドメインに存在する値を使用するだけです。それらを(リテラルとして)記述するか、関数を他のいくつかの値に適用した結果です。それらに名前を付けて(したがって定数を定義する)、同じ値がプログラムの別の場所で使用されるようにすることができます。関数適用は計算としてではなく、与えられた引数への適用の結果として認識されるべきであることに注意してください。書き込み5+2
または書き込み7
は同じです。これは前の段落と一致しています。
必須の変数はありません。割り当てはできません。割り当て可能な変数に名前をバインドできる命令型言語とは異なり、(定数を形成するために)名前のみを値にバインドできます。
それが複雑さを犠牲にするかどうかは完全に不明です。1つには、複雑さは命令パラダイムに関係していることを参照します。関数型プログラミングでは、関数型プログラムを命令型プログラムとして読むことを選択した場合を除き、そのように定義されていません。これは、設計者の意図ではありません。実際、機能ビューは、そのような問題を心配せず、計算されているものに集中できるようにすることを目的としています。それは仕様と実装のようなものです。
コンパイラーは実装を管理し、実行するハードウェアが何であれ、実行するハードウェアに最適化できるように十分にスマートでなければなりません。
プログラマがそんなことを心配する必要がないと言っているのではありません。また、プログラミング言語やコンパイラテクノロジが、私たちが望むほど成熟していると言っているわけではありません。
質問に答える
既存の値(エイリアンの概念)を変更するのではなく、必要に応じて異なる新しい値を計算します。おそらく、それがリストである追加の要素を1つ持つことによってです。
プログラムは新しいデータを取得できます。重要なのは、それを言語でどのように表現するかです。たとえば、プログラムが1つの特定の値(おそらくサイズに制限がない)で機能することを考慮することができます。これは入力ストリームと呼ばれます。それはそこに座っているはずの値です(すでに完全にわかっているかどうかは問題ではありません)。次に、ストリームの最初の要素と残りのストリームで構成されるペアを返す関数があります。
これを使用して、純粋に応用的な方法でコミュニケートするコンポーネントのネットワークを構築できます(コルーチン)
機械学習は、データを追加して値を変更する必要がある場合のもう1つの問題です。関数型プログラミングではこれを行わず、トレーニングデータに応じて適切に異なる新しい値を計算するだけです。結果のマシンも動作します。心配しているのは、時間とスペースの効率の計算です。しかし、これもまた別の問題であり、理想的にはコンパイラーが対処する必要があります。
最後の発言
コメントやその他の回答から、実用的な関数型プログラミング言語は純粋に関数型ではないことは明らかです。これは、特にコンパイルに関しては、当社のテクノロジーがまだ改善されていないという事実を反映しています。
純粋に応用的なスタイルで書くことは可能ですか?答えは約40年前から知られており、「はい」です。1970年代に登場した表記セマンティクスのまさに目的は、言語を純粋に機能的なスタイルに翻訳(コンパイル)することであり、数学的に理解が深まり、プログラムのセマンティクスを定義するためのより良い資金と考えられていました。
興味深い点は、変数を含む命令型プログラミング構造は、データストアなどの値の適切なドメインを導入することにより、関数スタイルに変換できることです。そして、関数型のスタイルにも関わらず、命令型で書かれた実際のコンパイラーのコードに驚くほど似ています。