モナド

#functional-programming #haskell

値を文脈(コンテキスト)付きで包み、その文脈を保ったまま計算を繋げていくための仕組み。関数型プログラミング(特にHaskell)で、失敗しうる計算・状態・入出力など「純粋な関数だけでは表現しにくいもの」を統一的に扱うための型クラス/デザインパターン。Currying(カリー化)と並んで関数型プログラミングの基本語彙のひとつ。

一言でまとめると「包んだ値に対する計算の連結方法を、型ごとに定義できる共通インターフェース」。

構成要素

モナド M は2つの操作を持つ。

  • return (unit) — 普通の値 a をモナドの値 M a に包む。例: return 5Just 5
  • bind (>>=) — M a と「a → M b な関数」を受け取り、包みを開けて関数を適用し、結果をまた M b として返す。これで「文脈付き計算の連結」ができる

モナド則

正しいモナドは3つの法則を満たす必要がある。Haskellコンパイラは検査しないので、インスタンスを書くプログラマの責任。

  1. 左単位元: return x >>= ff x
  2. 右単位元: m >>= returnm
  3. 結合律: (m >>= f) >>= g(\x -> f x >>= g)m を bind したものと同じ

この3つが成り立つおかげで、do記法で書いた逐次的なコードが直感通りに動くことが保証される。

代表的なモナド

モナド 文脈 何が嬉しいか
Maybe 失敗するかもしれない Nothing が出たら以降を自動スキップ。nullチェックの連鎖が消える
Either エラー情報付きの失敗 エラーを値として伝搬
List 非決定性(複数の結果) 全組み合わせの計算が自然に書ける
IO 副作用 純粋な言語の中に入出力を閉じ込める
State 状態の引き回し 状態渡しの定型コードを隠蔽

Maybe の例。bindが Nothing を自動で伝搬してくれるので、手書きなら「結果を確認して、Nothingでなければ次へ…」となるif連鎖が消える。

lookupUser name >>= lookupAddress >>= lookupZipCode
-- どこかで Nothing になれば、最終結果も Nothing

JavaScriptの Promise.then やRustの Option/Resultand_then も、実質的に同じ構造(bind相当)を持っている。

共通インターフェースだと何が嬉しいのか

モナドの価値は個々の MaybeIO そのものではなく、それらを貫く共通の「形」に名前を付けた点にある。形に対する道具(汎用関数・構文・リファクタリング則)を一度作れば全部の型で使い回せる。

1. 定型処理(配管コード)がロジックから消える

「失敗チェックして次へ」「状態を次の関数に手渡し」「エラーを上に伝搬」といった処理は、本来やりたい計算とは無関係の"配管"。これを bind の定義に一度だけ押し込むと、利用側のコードにはビジネスロジックだけが残る。

2. 汎用関数が「無料で」ついてくる

bindreturn だけを使って書かれた関数は、すべてのモナドに対して自動で動く。Haskellの Control.Monad には mapM/forM(for-eachループ相当)、sequence[M a]M [a])、replicateMwhenfoldM などが揃っていて、自分の型に Monad インスタンスを定義した瞬間、これら全部が使えるようになる。Iterator インターフェースを実装すれば map/filter が全部使えるのと同型の嬉しさ。

3. 言語側の構文サポートが1つで済む

Haskellの do 記法は「モナドという単一のインターフェース」への糖衣構文なので、言語は構文を1つ用意するだけで、失敗処理にも状態にも非同期にも同じ書き味を提供できる。共通化しない場合、JavaScriptが Promise 専用に async/await を、Rustが Result 専用に ? を用意したように、文脈の種類ごとに専用構文を言語に足していくことになる。

4. 文脈の差し替えがロジックの書き換えなしにできる

ロジックがインターフェース越しに書かれていれば、「MaybeEither に変えたい」「後からログ蓄積を足したい」というとき、モナドの定義側を差し替えるだけでロジック側はそのまま動く。モナド則が保証されているおかげで、差し替えやリファクタリングをしても挙動の予測が崩れない。

圏論との関係

「モナドは自己関手の圏におけるモノイド対象」という圏論由来の定義もあるが、プログラミングで使う分には上記の「共通インターフェース」理解で十分。

出典

作成日時: 2026-08-13 09:43 / 更新日時: 2026-08-13 09:43