C#での関数型プログラミング

当社開発部門の山本です。

オークソリューションズではVisual Studioを使用してC#による開発を行っています。
これまで主にオブジェクト指向プログラミング(OOP)を中心にシステムを構築してきましたが、
最近では、コードの保守性や再利用性、バグの低減を目的として、関数型プログラミングの手法を勉強しています。
Haskellや、Haskellの理解を深めるために圏論を勉強しました。
また関数型プログラミングだけではなく、ドメイン駆動設計(DDD)や、初心に戻りデザインパターンをSOLID原則の観点から学びなおしています。
いままで会社全体で勉強する機会がなくずっと独学だったのですが独学に比べて実践で使える形で身についてるように感じます。

関数型プログラミングの主な特徴は以下の通りです。

  1. 純粋関数
    同じ入力に対して常に同じ出力を返し、副作用がない関数。
    副作用なないということは複数のスレッドやプロセスで同じ関数を同時に実行しても、互いに干渉することなく正しい結果が得られます。
    C#では純粋関数を直接サポートしていませんが、関数内で外部の状態にアクセスしないようにしたり値オブジェクトなどのイミュータブルなデータ構造を使用したりすることで純粋関数に近いふるまいを実現することができます。
  2. 高階関数
    関数を引数に取ったり、返り値として返す関数。
    高階関数を使用してできることは以下になります。
    • 処理の抽象化・共通化
      汎用的な処理を抽象化し、同じロジックを異なるデータや操作に対して再利用する。
       使用例としてはmap関数やfilter関数といったコレクションの各要素に対して特定の操作を適用し、その結果から新しいコレクションを生成するものになります。
    • 関数の合成
      小さな関数を組み合わせて、より複雑な関数を作ります。
      これにより、コードの可読性と保守性が向上します。
    • カリー化
      関数が複数の引数を取る代わりに、1つの引数を取る関数を返すように変換する技法。
      関数に対して一部の引数を先に適用し、もとの関数の残りの引数を引き取り結果を返す関数にすることができます。
    • コールバック関数
      非同期処理やイベント駆動プログラミングにて関数に引数として渡し、その関数が特定の条件やイベントの際に呼び出す関数です。
    • C#ではFuncデリゲートやActionデリゲートと呼ばれる関数を格納するオブジェクトを用いて高階関数を記述できます。
      またLINQ(言語統合クエリ)のメソッドは、関数を引数に取る高階関数として実装されています。
  3. イミュータブル変数
    データの不変性を保ち、変更を加えない変数。
    C#では、readonlyフィールドやimmutableコレクションを使って不変データを扱うことができます。
    勉強するまではイミュータブルって変更があるたびにオブジェクトを作り直すのは不便では?と思っていましたが、値が変わらないということは変数を未知の関数に渡しても値が変更されているかどうか知るために関数の中身を見なくてよく、コードの可読性が高くなります。

関数型プログラミングの概念を理解し、適用することで、より予測可能で保守しやすいコードを書くことができます。
ただし、関数型プログラミング言語に実装されているResult型(Either型)がC#には実装されてなくエラー処理を簡潔に書くためには結局「Rust」や「F#」などの関数型プログラミング言語で実装するか、C#に実装されるのを待つしかないようです。

話は変わりますが、今月発売の「なぜ依存を注入するのか DIの原理・原則とパターン」という本を注文しました。
依存性の注入(DI:Dependency Injection)は今まで勉強してきた内容に含まれており、SOLID原則のD、「依存性逆転の原則」を実現するための手段であると理解していますが、完全に理解できているかこの本で確認したいと思います。

お問い合わせ
Contact

TOPへ戻る