関数型プログラミング

関数合成 かんすうごうせい

関数型プログラミングコンポジションパイプライン純粋関数カリー化高階関数
関数合成について教えて

簡単に言うとこんな感じ!

「洗う→すすぐ→乾かす」みたいに、小さな処理をベルトコンベアのようにつなげて、大きな処理を作る仕組みだよ!それぞれの工程がシンプルだから、組み合わせ次第でどんな複雑な処理でも作れるんだ。


関数合成とは

関数合成(Function Composition)とは、「ある関数の出力を別の関数の入力として渡す」ことを繰り返し、複数の小さな関数を1本のパイプラインとしてつなげるプログラミングの技法です。数学の合成関数 f(g(x)) をそのままコードで表現したものと言えます。

たとえば「文字列を小文字にする」関数と「空白を取り除く」関数を合成すると、「小文字にして空白も除く」という新しい関数が生まれます。処理を細かく分割して部品化し、それを組み合わせることで複雑な機能を実現するのが関数合成の本質です。

関数合成は関数型プログラミング(Functional Programming)の中核的な考え方のひとつで、コードの再利用性・テストのしやすさ・バグの追いにくさを大幅に改善します。「1つの関数が1つのことだけをする」というシンプルな設計原則と非常に相性が良い手法です。


関数合成の仕組み

関数合成のイメージは「処理のベルトコンベア」です。データが左から右へ流れ、各ステーションで変換が施されます。

入力データ


 関数 A(小文字化)


 関数 B(空白除去)


 関数 C(先頭大文字化)


出力データ

数学的には h(x) = f(g(x)) と書きます。コードでは次のように表現されます。

言語合成の書き方
JavaScriptconst h = x => f(g(x)) / ライブラリで compose(f, g)
Pythondef compose(f, g): return lambda x: f(g(x))
Haskellh = f . g. 演算子が合成そのもの)
Scalaval h = f compose g

覚え方:「右から左」に読む

合成した関数 compose(f, g) は、実行順序は g → f(右から左)です。数学の記法 f∘g と同じで「g を先にやって、その結果を f に渡す」順番になります。混乱しやすいポイントなので「compose は右が先!」と覚えておきましょう。

パイプライン演算子(|>)を使う言語やライブラリでは左から右に読めるので、直感的に理解しやすくなります。

合成できる関数の条件

条件説明
出力と入力の型が合う前の関数の出力型 = 次の関数の入力型でないとつなげられない
純粋関数であること副作用(ファイル書き込みなど)がないと予測可能な合成になる
1つの引数を取る複数引数の関数はカリー化して1引数に変換すると合成しやすい

歴史と背景

  • 1930年代 — 数学者アロンゾ・チャーチがラムダ計算(λ計算)を提唱。関数の合成という概念の数学的基盤が生まれる
  • 1958年 — LISPが誕生。関数を値として扱える最初期のプログラミング言語として、合成の概念を実装に持ち込む
  • 1970年代 — MLやHaskellの前身となる研究が進み、型システムと関数合成の相性の良さが証明される
  • 1990年 — Haskellが公開。.(ドット演算子)による簡潔な合成記法が普及し、関数合成がプログラミング言語機能として一般化
  • 2010年代 — JavaScript・Python・Scalaなど主流言語でも関数型スタイルが取り入れられ、compose / pipe 系のユーティリティが広く使われるようになる
  • 現在 — フロントエンド(React / Redux)・バックエンド・データ処理など、あらゆる領域で関数合成の考え方が活用されている

関連する技術・概念との比較

関数合成は単独で使う技法ではなく、関連する概念とセットで理解するとより深く使いこなせます。

関数合成と関連概念のマップ 関数合成 Function Composition 純粋関数 Pure Function カリー化 Currying 高階関数 Higher-Order Fn パイプライン Pipeline モナド Monad 副作用なしで合成が安全に 多引数関数を1引数に 関数を引数・戻り値に 左→右の直感的な合成スタイル 文脈付き合成へ発展
概念関係一言説明
純粋関数合成の前提条件副作用がないから安全につなげられる
カリー化合成を助ける変換多引数関数を1引数ずつに分解し合成可能にする
高階関数合成を実現する仕組み関数を引数や戻り値として扱えるから合成ができる
パイプライン合成の書き方の一種左→右の順に読める合成スタイル(`
モナド合成の発展形非同期・エラー・副作用などを含む文脈付きの合成

パイプラインとの違い

「合成」と「パイプライン」はほぼ同じことを指しますが、書き方と読み方向が逆です。

// 合成(compose): 右から左に実行
const result = compose(capitalize, trim, toLowerCase)(input);
//                          ↑ 実行順: toLowerCase → trim → capitalize

// パイプライン(pipe): 左から右に実行(直感的)
const result = pipe(toLowerCase, trim, capitalize)(input);
//                  ↑ 実行順: toLowerCase → trim → capitalize

ビジネス的な処理フローを説明するときはパイプラインの書き方のほうが読みやすいため、現代の多くのライブラリ(Ramda, fp-ts, RxJSなど)ではパイプラインスタイルが好まれます。


実務での活用シーン

関数合成は理論だけでなく、実際の開発現場でも広く使われています。

シーン具体例
データ変換APIレスポンスの正規化・フィルタ・整形をパイプラインで処理
フォームバリデーション「必須チェック→文字数チェック→形式チェック」を合成
ミドルウェアExpress.jsのミドルウェア、Reduxのenhancerはまさに関数合成
ログ・認証の横断処理ロギングや認証処理を合成して本処理に被せる
データパイプラインETL処理(Extract→Transform→Load)を関数合成で表現

関連用語

  • 高階関数 — 関数を引数や戻り値として扱える関数。合成を実現する土台
  • 純粋関数 — 副作用のない関数。合成を安全に行うための前提条件
  • カリー化 — 多引数関数を1引数ずつの関数に変換する技法。合成をしやすくする
  • ラムダ式 — 名前のない無名関数。関数合成で頻繁に使われる
  • 関数型プログラミング — 関数合成を中心的な設計手法として採用するプログラミングパラダイム
  • モナド — 非同期・エラーなど文脈を持つデータを含む「発展版の関数合成」
  • パイプライン演算子|> などで左→右に関数をつなぐ演算子。合成の書き方のひとつ
  • イミュータブル — 値を変更しない設計方針。純粋関数・関数合成と相性が良い