9 ポイント 投稿者 bboydart91 2026-02-08 | 2件のコメント | WhatsAppで共有

本文

  • ファンクターの map だけでは解決できない2つの問題(コンテナ内に関数が閉じ込められる問題、合成時に文脈が入れ子になる問題)から出発し、アプリカティブファンクターとモナドに至る過程をTypeScriptコードで説明
  • 1988年にエウジェニオ・モッジ(Eugenio Moggi)がプログラムを A → B ではなく A → T(B) としてモデル化した背景から始める
  • flatMap = map + join という構造と、これを安全に使うための3つの法則(結合、左単位、右単位)を扱う
  • モナドがなぜ "自己関手圏のモノイド対象" なのかを、整数加算のモノイドと対比して説明
  • Promise はモナディックに動作するが、厳密な数学的意味でのモナドではない理由にも触れる

ファンクターの限界: map ではできないこと

  • カリー化された関数を map で適用すると、結果が Maybe<(b: number) => number> のように関数がコンテナ内に閉じ込められる
    • map はコンテナ外の関数しか受け取れないため、中に閉じ込められた関数を別の値に適用する方法がない
  • ファンクターを返す2つの関数を合成すると、Maybe<Maybe> のように文脈が入れ子になる
    • ステップが増えるほど Maybe<Maybe<Maybe<...>>> と無限に入れ子になる

アプリカティブファンクター: コンテナ内の関数を適用する

  • apply 演算により、コンテナ内に閉じ込められた関数を別のコンテナの値に適用できる
    • apply: T<(A → B)> → T<A> → T<B>
  • pure 演算で純粋な値をコンテナに挿入する
  • 限界: どのコンテナを合成するかを事前に決めておく必要がある
    • 前の計算結果を見て次の計算を決めるような、動的な逐次依存関係は表現できない

モナド: 入れ子を平坦化する演算の発明

  • join 演算が T<T<A>> → T<A> として二重コンテナを単一に平坦化する
    • JavaScript の Array.prototype.flat が同じ役割を果たす
  • 実務では map + join を組み合わせた flatMap を使う
    • flatMap: T<A> → (A → T<B>) → T<B>
    • mapA → B を受け取るが、flatMapA → T<B> を受け取ることで結果を1層に保つ

flatMap の3つの法則

  • 結合法則: 三重入れ子 T(T(T(A))) を平坦化するとき、内側から平坦化しても
    外側から平坦化しても結果は同じでなければならない
    • m.flatMap(f).flatMap(g) === m.flatMap(x => f(x).flatMap(g))
  • 左単位法則: pure で入れてすぐに flatMap すると、関数を直接適用したのと同じ
    • pure(a).flatMap(f) === f(a)
  • 右単位法則: flatMappure を渡すと元のコンテナのまま
    • m.flatMap(pure) === m

"自己関手圏のモノイド対象" を分解する

  • プログラミングにおけるファンクターは型の世界から型の世界へ向かうので、エンドファンクター(自己関手)である
  • エンドファンクターそのものを対象とするエンドファンクター圏を構成できる
  • モノイドの要件(二項演算 + 結合法則 + 単位元)に当てはめると:
    • 二項演算 = join
    • 単位元 = pure
    • 整数加算のモノイドと構造が正確に対応する

Promise はなぜモナドではないのか

  • then が返り値に応じて mapflatMap を混在させて処理する
  • Promise<Promise> 状態がランタイムで許容されず、即座に単一の
    階層へ統合される
  • 実務上は便利だが、数学的なモナド則は満たさない

2件のコメント

 
calofmijuck 2026-02-08

Comonadについても扱ってください!

 
bboydart91 2026-02-09

うあ…考えてみます(笑)