これは理論的な質問ですが、主にC++を使用した「通常の」命令テクニックが長年のプログラミングでわかった今、私はJavaScriptをさりげなく学習しているときに偶然偶然偶然見つけた関数型プログラミングの別の世界を発見しました。
これは、完全に状態指向のプログラムを純粋に機能的で状態のない別の実装に技術的に置き換えることができるかどうか疑問に思いました。
これは興味深いアイデアであり、関数型プログラミングには明快さと優雅さがあり、本当に頭を悩ませています。
短い答え:はい。ウィキペディアによると、計算の普遍的なモデルとしてのチューリング機械に対する ラムダ計算 の同等性は、アランチューリングによって1937年に示されました。チューリングマシンの計算モデルは、命令型プログラミングまたはステートフルプログラミングについて話すときに一般的に考えているものであり、ラムダ計算は「純粋な関数型プログラミング」の数学的な形式化です。
すべての効果的な計算モデルは、チューリングマシンと同じ計算を実行でき、その逆も可能であると推測されます。これは Church-Turing論文 と呼ばれます。しかし、この推測は、多かれ少なかれ直感的な用語「効果的な計算モデル」のために証明することはできません(おそらく誰かが将来新しいモデルを発明するでしょうか?)
どんな動的システムでも、「状態」は現在が過去または未来の影響を受けるようにするものです(時間の矢はありません)数学的な問題、単なる物理的な制約)。
「覚えておくべき」何かがあるかどうか、またはそれがあなたの行動に依存するかどうか、あなたは状態を持っています。
状態のないシステムは「動的」ではなく、単なる組み合わせ関数です。これには状態がない可能性がありますが、異なる結果を生成するには、何らかの方法で状態を指定する必要があります。
これで、参照する計算モデルに応じて、状態を明示的に(変数の形式で)または暗黙的に(「戻りアドレス」の形式で)表すことができます。
fna(fnb(x))
を実行すると、fnbに状態が与えられ、fnaの状態が生成されます。これは、fnbが呼び出される前にx
が存在するためです(つまり、それはそれ自体の「過去」からのものです)。
「状態が存在する」や「状態が存在しない」の問題ではありません。 「気にする」か「しない」の母校です。
状態とは、現在の刺激だけに基づくのではなく、過去の刺激に依存する方法で現在の刺激に応答する能力を意味します。
純粋に関数型のプログラムは単なる関数です。したがって、実際のアプリケーションでは、純粋に機能的なプログラムはペア(old_state * present_stimulus)を入力し、ペア(new_state * present_response)を出力します。次の刺激を待ち、状態を伝播するには、外部のステートフルな「ルーパー」が必要です。
純粋に関数型のプログラムは本質的に状態を持たず、実際のアプリケーションに直接使用することはできません。
したがって、no状態指向のプログラムは、純粋に機能的で状態のない別の実装に置き換えることができます。
外の世界と対話する必要がない限り、明示的な変更可能な状態を回避できます。
JavaScriptでは、プログラムが実際にプロセッササイクルを占有する以上の効果を発揮するために、DomまたはWindowオブジェクトを変更する必要があり、これらのAPIはステートフルです。ただし、DomオブジェクトとWindowオブジェクトをパラメーターとしてJavaScriptコードに渡し、新しいDom/Windowを出力として受け取るラッパーを作成できると思います。これにより、JavaScriptコードが変更可能な状態から分離されます。
もちろん、ブラウザウィンドウとDOMは本来ステートフルなので、あなたはまだ依存状態です。対話型アプリケーションは本質的にステートフルですが、明示的な状態を最小限にするなどの方法でコードを構築することもできます。
別の質問は、それが良いアイデアかどうかです。設計上純粋な関数型言語であるHaskellでさえ、変更可能な状態をシミュレートできる 'state'モナドが含まれています。これは、明示的な変更可能な状態が、実際には望ましいパターンであることを示しています。
ステートのないプログラミング言語で「ステートマシン」を実装する方法について考えてください。
おそらく実際にそれを行うことができますが、関数名をストレージとして使用することになります。最終的には次のようなゴブリーデイグックで終わる:
if (sm.atBegining()) sm.start() else if (sm.done()) sm.stop() ) else sm.progress()