関数型プログラミング
計算を関数の組み合わせとして表現し、可変状態や副作用をできるだけ局所化する考え方。
概要
関数型プログラミングは、計算を関数の組み合わせとして表現し、可変状態や副作用をできるだけ局所化する考え方です。
同じ入力に対して同じ結果を返し、外部の状態を変更しない純粋関数を中心に組み立てると、処理を部分ごとに理解しやすくなります。
HaskellやClojureは関数型の特徴が強い言語です。Javaでも、ラムダ式、Stream API、不変オブジェクトなどを通して関数型の考え方を利用できます。
例
注文金額の合計をJavaのStream APIで求めます。
int total = items.stream()
.mapToInt(item -> item.getPrice() * item.getQuantity())
.sum();
「合計値を0から更新していく手順」ではなく、「各要素を金額へ変換し、その合計を求める」という計算の関係を表しています。
主な考え方
- 純粋関数: 同じ入力から同じ出力を返し、外部状態を変更しない
- 不変性: 作成した値を変更せず、新しい値を作る
- 高階関数: 関数を引数や戻り値として扱う
- 関数合成: 小さな関数を組み合わせて処理を作る
- 副作用の分離: DB、ファイル、通信、現在時刻などへの依存を境界へ寄せる
メリット
- 状態変更が少なく、処理結果を予測しやすい
- 小さな関数を単独でテストしやすい
- データ変換の流れを簡潔に表現できる
- 共有する可変状態を減らせるため、並行処理と相性がよい
- 関数を組み合わせて処理を再利用しやすい
デメリット
- 慣れていないと、関数合成や抽象化を読みにくく感じる
- 入出力やDB更新など、現実の副作用を完全にはなくせない
- 不変データを多用すると、用途によってはメモリや性能への配慮が必要になる
- 高度な型や抽象化を使いすぎると、チーム内の理解コストが上がる
- 単純な逐次処理を無理に関数の連鎖へすると、かえって読みにくい
向いている場面
- コレクションやストリームの変換
- 入力から出力を求める計算
- 検証ルールや価格計算
- 並行・並列処理
- 副作用を分離しやすいドメインロジック
副作用との付き合い方
Webアプリケーションでは、DB更新やAPI通信を避けることはできません。関数型の目的は、副作用をゼロにすることではなく、計算部分と副作用のある部分を分け、影響範囲を明確にすることです。
たとえば、金額計算は純粋関数として実装し、計算結果を保存する処理はRepositoryなどの境界へ分けられます。
更新履歴
- 初版作成