アプリカティブファンクター(Applicative)

アプリカティブファンクター(Applicative Functor)は、関数型プログラミングにおいてファンクター(Functor)とモナド(Monad)の中間に位置する抽象化であり、文脈を持つ値(例えばオプション型、リスト、IOなど)に対して関数の適用を構造的に行うためのインターフェースを提供します。


1. 背景:Functor → Applicative → Monad

  • Functormap(または fmap)を提供し、「文脈内の値」に通常の関数を適用する仕組み。

  • Applicative は Functor を拡張し、「文脈内の関数を文脈内の値に適用」できるようにする。

  • Monad は Applicative をさらに拡張し、「文脈を動的に変更」する(flatMapbind)機能を持つ。


2. 型クラスとしての Applicative(Haskell風の定義)

h
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b

説明

  • pure:通常の値を文脈(ファンクター)に持ち上げる。

  • <*>(apply演算子):文脈内の関数 f (a -> b) を文脈内の値 f a に適用して f b を得る。


3. 動作例(Option型で考える)

scala
// Scala(Optionの例) val f: Option[Int => Int] = Some(x => x + 1) val x: Option[Int] = Some(3) val result: Option[Int] = f <*> x // 結果は Some(4)

fx も Option という「文脈」にあるが、Applicative を使うことで f に包まれた関数を x に包まれた値に適用できる。


4. Applicativeの利点と役割

並列的な構成が可能(モナドと比較して)

Applicative は各引数が独立に評価できる場合に有用で、例えば以下のようなケースに適しています:

  • 複数の入力を同時に処理(例えば複数のバリデーション)

  • パーサー合成

  • 並列計算(特に FutureTask 型の文脈)

静的な構造が保たれる

Applicative は文脈を「静的に」保つ(pure<*> だけで完結する)ため、プログラムの評価構造がモナドに比べてわかりやすい。


5. 実装例:ValidationにおけるApplicative

モナドでは一つのエラーで計算が止まるが、Applicativeを使えば全てのバリデーションを行い、全てのエラーを集めることができる:

scala
// 擬似コード:Validation型(成功か、複数のエラー) val nameCheck: Validation[List[String], String] val ageCheck: Validation[List[String], Int] val person: Validation[List[String], Person] = (nameCheck, ageCheck).mapN(Person.apply)

ここで .mapN は Applicative の <*> を複数引数に拡張した形で、Person コンストラクタを文脈の中で適用する。


6. まとめ

観点 Functor Applicative Monad
文脈付き値への適用 map <*> flatMap
文脈内の関数の適用 ×
文脈間の依存 × ×(独立) 〇(依存関係を持つ)
並列性 制限あり 高い 低い(逐次)

Applicativeは、「関数適用の文脈化」を可能にすることで、関数型プログラミングにおけるコードの構造化と再利用性を高める強力な抽象です。モナドほど強力ではありませんが、構造がシンプルな分、解析やテストがしやすいという利点があります。

必要に応じて、具体的な実装例(Scala, Haskell, TypeScript など)も提供できます。

生成日:2025/06/01