どのように私は、次のすべてを持っているシステムを構築します。
- 不変オブジェクトで純粋な関数を使用します。
- 関数が必要とする関数データのみに渡し、それ以上(つまり、大きなアプリケーション状態オブジェクトはなし)
- 関数への引数が多すぎることは避けてください。
- 関数に渡されるパラメーターが多すぎるのを避けるために、関数にパラメーターをパックおよびアンパックするためだけに新しいオブジェクトを作成する必要はありません。複数のアイテムを単一のオブジェクトとして関数にパックする場合、一時的に構築されたものではなく、そのオブジェクトをそのデータの所有者にしたい
Stateモナドはルール2に違反しているように思えますが、モナドを介して織り込まれているため明らかではありません。
どういうわけかレンズを使用する必要があると感じていますが、非機能言語についてはほとんど書かれていません。
バックグラウンド
演習として、既存のアプリケーションの1つをオブジェクト指向スタイルから機能スタイルに変換しています。私が最初にやろうとしているのは、アプリケーションの内部コアをできるだけ多く作成することです。
私が聞いたことの1つは、純粋に機能的な言語で「状態」を管理する方法であり、これは私がステートモナドによって行われていると信じていることです。 「そのままの世界」を選択し、関数が戻ると、変化した世界の状態を返します。
たとえば、純粋に機能的な方法で「hello world」を実行する方法は、プログラムに画面の状態を渡し、「hello world」が印刷された画面の状態を受け取るようなものです。技術的には、純粋な関数を呼び出しているので、副作用はありません。
それに基づいて、アプリケーションを調べました。1。最初に、すべてのアプリケーション状態を単一のグローバルオブジェクト(GameState)に入れます。2。次に、GameStateを不変にしました。変更することはできません。変更が必要な場合は、新しいものを作成する必要があります。これを行うために、コピーコンストラクターを追加しました。オプションで、変更された1つ以上のフィールドを使用します。3.各アプリケーションに、GameStateをパラメーターとして渡します。関数内で、予定通りの処理を行った後、新しいGameStateを作成して返します。
純粋に機能的なコアと、そのGameStateをアプリケーションのメインワークフローループにフィードする外側のループの仕組み。
私の質問:
さて、私の問題は、GameStateには約15種類の不変オブジェクトがあることです。最下位レベルの関数の多くは、スコアの保持など、これらのオブジェクトの一部のみで動作します。それで、スコアを計算する関数があるとしましょう。今日、GameStateはこの関数に渡され、新しいスコアで新しいGameStateを作成してスコアを変更します。
それについて何かが間違っているようです。この関数はGameState全体を必要としません。スコアオブジェクトが必要です。そこで、スコアを渡すように更新し、スコアのみを返します。
それは理にかなっているように思えたので、私は他の機能をさらに使いました。一部の関数では、GameStateから2、3、または4つのパラメーターを渡す必要がありますが、アプリケーションの外側のコア全体でパターンを使用しているため、ますます多くのアプリケーション状態を渡しています。たとえば、ワークフローループの先頭で、メソッドを呼び出し、メソッドを呼び出すメソッドなどを呼び出して、スコアが計算されるまで続けます。つまり、一番下の関数がスコアを計算するという理由だけで、現在のスコアがこれらすべてのレイヤーに渡されます。
だから今私は時々数十のパラメータを持つ関数を持っています。これらのパラメーターをオブジェクトに入れてパラメーターの数を減らすこともできますが、そのクラスは、単に渡すことを避けるために呼び出し時に単純に構築されるオブジェクトではなく、状態アプリケーション状態のマスターの場所にしたいです複数のパラメータで、それらを解凍します。
だから今、私が持っている問題は私の関数があまりにも深くネストされていることだろうかと思っています。これは小さな関数が必要なためです。そのため、関数が大きくなったらリファクタリングし、複数の小さな関数に分割します。しかし、そうすることでより深い階層が生成され、外部関数が直接それらのオブジェクトを操作していない場合でも、内部関数に渡されたものはすべて外部関数に渡される必要があります。
この問題を回避する方法に沿って単にGameStateを渡すように見えました。しかし、関数が必要とする以上の情報を関数に渡すという元の問題に戻りました。