関数型プログラミングのコアアイデア

関数型プログラミングは、近年ますます人気が高まっています。関数型プログラミングのある言語は、関数型プログラミングのない言語を軽蔑し、純粋な関数型プログラミングのある言語は、純粋な関数型プログラミングではない言語を軽蔑します。

それで、関数型プログラミングとは正確には何ですか、そして関数型プログラミングのコアアイデアは何ですか?

関数型プログラミングの最初の機能は、関数をパラメーターとして別の関数に渡すことができることです。これは、いわゆる高階関数です。たとえば、配列を並べ替えるには、並べ替え関数をパラメーターとして渡すことができます。

String [] array = {"orange"、 "Pear"、 "Apple"};
Arrays.sort(array、String :: compareToIgnoreCase);
関数型プログラミングの2番目の機能は、関数を返すことができることです。閉じたパッケージまたは怠惰な計算:

上記の2つの機能は、コードを単純化するだけです。コードの保守性に関して、関数型プログラミングの最大の利点は参照透過性です。つまり、関数の実行結果は入力パラメーターのみに依存し、外部状態には依存しません。したがって、関数型プログラミングには副作用がないとよく言われます。

大きな利点がある副作用はありません。つまり、関数は内部でステートレスです。つまり、入力は確実で、出力は確実であり、テストと保守が簡単です。

多くの初心者は、変数と副作用を排除する言語であるHaskellだけが本物の関数型プログラミングであると考えて、「純粋な」関数型言語に苦労する傾向があります。一部の人々は、純粋関数はロギングを含むIO操作を持つことができないとさえ考えています。

実際、この種の絡み合いは、コンピューターの下部が完全に可変のメモリと予測不可能な入力システムであるため、意味がありません。副作用のない完全性の追求は非現実的です。関数型プログラミングの概念を理解するだけで、ビジネスロジック。「副作用なし」に関しては、変数、ロギング、読み取りキャッシュなどの重要でない「副作用」については、まったく心配する必要はなく、解決する必要もありません。解決することはほとんど不可能です。

栗をあげましょう。

たとえば、金融ソフトウェアには個人所得税を計算する関数が必要です。入力はIncomeRecordで、出力は税額です。

doublecalculateIncomeTax(IncomeRecord record){ } IncomeRecordが次のようになっていると仮定します。


class IncomeRecord { String id; // ID Number String name; // Name double salary; // Salary }まず、5つの社会保険と1つの住宅 基金のような厄介なことは考慮しません。税金を計算します。簡単にするために、免除額を直接差し引いた後、計算は20%で計算されると仮定します。




doublecalculateIncomeTax(IncomeRecord record){ double threshold = 3500; double tax = record.salary <= threshold?0:(record.salary-threshold)* 0.2; returntax ; }上記のプログラムは2018年9月1日より前でした。問題ありません。問題は、2018年9月1日以降にしきい値が5000に調整されていることです。計算結果は2018年8月と2018年9月で異なるはずです。変更方法?




通常の開発者の改革:それは簡単ではありませんか?現在の日付を直接取得し、正しいしきい値を返します。

doublecalculateIncomeTax(IncomeRecord record){ double threshold = today()<date (2018、9、1 )?3500:5000; 二重課税= record.salary <=しきい値?0:(record.salary-しきい値)* 0.2; 還付税; }程序是没错、问题是:




8月31日に実行され、9月1日に実行される同じ入力では、結果は同じではありません。会計士は9月1日に8月の給与計算を行う必要があり、最初にコンピューターの時刻を8月に調整する必要がありますか?

関数型プログラミングの観点から考えてみると、問題が見つかります。

Today()この関数では、返される結果は時間に関連しているため、calculateIncomeTax()は純粋関数ではなく、現在の時間に関連しています。

次に、しきい値調整をサポートしながら、calculateIncomeTax()を純粋関数に復元する方法は?

この方法は、時間関連の変数をパラメーターとして渡すことです。たとえば、IncomeRecordにいくつかのフィールドを追加します。

class IncomeRecord { String id; // ID number String name; // name double salary; // salary int year; // year int month; // month }このようにして、today()呼び出しを排除できます。






doublecalculateIncomeTax(IncomeRecord record){ double threshold = date(record.year、record.month)<date(2018、9)?3500:5000; double tax = record.salary <= threshold?0:(record.salary-threshold )* 0.2;還付税; } calculateIncomeTax()は再び純粋な関数になり、会計はコンピューターの時間を変更する必要がありません。




この例は単純すぎると思いますか?実際、単純な関数をステートフルとして記述できる場合は、複雑なビジネスロジックをお粥のポットに書き込む必要があります。

複雑な栗を与える:

株式取引システムの場合、入力を次のように定義すると、市場が開く前のすべての株主の現金と株式保有、および取引期間中のすべての注文の場合、出力は市場が閉じた後のすべての株主の現金と株式保有です。

StockStatus process(StockStatus old、Listorders){ for(Order order:orders){ sendExchangeResult(…); //各トランザクションに情報を送信する} }明らかに、これは純粋関数ですが、プロセス中は、この関数は投資家の友達にさまざまなハートビートメッセージを送信します。







取引システムのモデルがそのような純粋関数として設計されている場合、理論的には、株式市場が開いた日からすべての注文を処理するだけでよく、今日の終了後にステータスを正しく取得できます。

つまり、ある日の開始前にシステムステータスのバックアップ(つまり、データベース全体のバックアップ)を取り、その日の順序を再処理する限り、の終了のステータスを取得します。当日。このプロセスは何度でも実行でき、結果は同じままであるため、コードの変更がビジネスプロセスに影響を与えるかどうかを確認するのに非常に適しています。

だから問題は、取引システムの無数の時間関連の状態を純粋関数にどのように処理するかということです。このモデルの処理は、税金の計算よりもはるかに複雑です。

これが関数型プログラミングの本質です。ビジネスシステムモデルはステートレスです。モデルの品質は、コードの正確性、信頼性、安定性、および996が必要かどうかに直接影響します。

おすすめ

転載: blog.csdn.net/qq_45424679/article/details/115104439