何かが変わる可能性があるからといって、それが不変のデータでモデル化できないという意味ではありません。
OOishスタイルで、次のようなものがあるとしましょう。
a = some_obj.calculationA(some, arguments);
b = some_obj.calculationB(more, args);
return combine(a, b)
明らかにcalculationA
、calculationB
に依存しており、両方の計算への入力としてsome_obj
手動でスレッド化することもできます。some_obj
オブジェクトに対してメソッドを呼び出すという観点から考えるので、それが自分がしていることであることに慣れていないだけです。
可能な限り最も明白な方法でHaskellに途中で翻訳すると、次のようになります。
let a = calculationA some_obj some arguments
b = calculationB some_obj more args
in combine a b
some_obj
とにかくそれがOOスタイルで行っていることなので、すべての関数に追加のパラメーターとして手動で渡すことは実際にはそれほど問題ではありません。
欠落している大きなことは、OOスタイルcalculationA
であり、calculationB
変更some_obj
される可能性があることです。これは、このコンテキストが戻った後にも使用される可能性があります。機能的なスタイルで対処することも非常に明白です。
let (a, next_obj) = calculationA some_obj some arguments
(b, last_obj) = calculationB next_obj more args
in (combine a b, last_obj)
私が物事を考えることに慣れている方法では、これは理論的な観点から、とにかくOOPバージョンで起こっていることです。命令型コードの特定の部分にアクセスできるすべての可変オブジェクトは、「実際には」追加の入力と追加の出力であり、秘密裏に暗黙的に渡されます。いたるところに数十の余分な入力と出力があるために機能的なスタイルがプログラムを複雑にしすぎると思う場合は、データフローがすべて残っているがあいまいになっているときに、プログラムが本当にそれほど複雑ではないかどうかを自問してください。
しかし、これはより高度な抽象化(モナドなどですが、それらだけではありません)が救いの手を差し伸べる場所です。モナドを魔法のように可変状態を与えるものとは考えないのが最善です。代わりに、それらをカプセル化パターンと考えてください。したがって、上記のようなコードを手動で記述する必要はありません。モナドを使用してState
「ステートフルプログラミング」を取得する場合、関数の入力と出力を介した状態のこのスレッド化はすべて引き続き実行されますが、厳密に管理された方法で実行され、これが実行されている関数はモナドによってラベル付けされます。タイプするので、それが起こっていることがわかります。