モナドっていうほど関数型プログラミング関係なさそうだよな

YAMAMOTO Yuji (山本悠滋)

2026-07-11 関数型まつり 2026

はじめまして! 👋😄

はじめまして! 👋😄

🇯🇵自己紹介 + 宣伝 1: Haskell-jp

🔰自己紹介 + 宣伝 2: Haskell入門コンテンツ

🟢自己紹介 + 宣伝 3: 私とモナド

Haskellを学んで以来、度々Haskellのモナドを解説してきました:

📝今日のゴール

⚠️おことわり

関数型プログラミングとは

純粋な関数を中心としたプログラミングだ
(本発表における定義)

純粋な関数とは

引数(入力)が同じであれば、常に同じ結果(出力)を返す関数

純粋な関数とは

純粋な関数とは

y = f(x)

純粋な関数だとやりやすいこと

純粋な関数だとやりづらい、というかできないこと

結果を戻り値として返す以外で表現する(副作用)

普通の関数: 引数の一部を直接書き換える

function setNAtZero(array, n) {
  result = array[0];
  array[0] = n;
  return result;
}

結果を戻り値として返す以外で表現する(副作用)

普通の関数: 引数の一部を直接書き換える

array  = [1, 2, 3];
result = setNAtZero(array, 9);
=> array  = [9, 2, 3]
=> result = 1

結果を戻り値として返す以外で表現する(副作用)

普通の関数: 引数の一部を直接書き換える

array  = [1, 2, 3];
result = setNAtZero(array, n);
// 👆だけじゃなく、    👆
//                  👆
//                  👆にも影響を与えてる!!

結果を戻り値として返す以外で表現する(副作用)

純粋な関数で似たようなことをするには?

function setNAtZeroPure(array, n) {
  result = array[0];
  // set: 指定したインデックスの値を
  //      置き換えたバージョンの配列を返す関数。
  //      元の配列は書き換えない。
  newArray = set(array, 0, n);
  return [newArray, result];
}

結果を戻り値として返す以外で表現する(副作用)

使用例

array0  = [1, 2, 3];
[array1, result1] = setNAtZeroPure(array0, 0);
[array2, result2] = setNAtZeroPure(array1, 1);
[array3, result3] = setNAtZeroPure(array2, 2);

異常系の結果をまとめて処理する(例外処理)

普通の関数: 例外を投げることで、一箇所のcatchで処理する

function getAt(array, n) {
  if (n < 0 || n >= array.length) {
    throw Error("Index out of bounds");
  }
  return array[n];
}

異常系の結果をまとめて処理する(例外処理)

使用例:

try {
  result1 = getAt(array, 1);
  result2 = getAt(array, 2);
  result3 = getAt(array, 3);
} catch (e) {
  console.log("Error: " + e.message);
}

異常系の結果をまとめて処理する(例外処理)

🙅‍♀️getAtは純粋?

try {
  result1 = getAt(array, 1);
  // 👆 result1 だけじゃなく...
  // ...
} catch (e) {
  // 👆 e にも影響を与えうる!
  console.log("Error: " + e.message);
}

異常系の結果をまとめて処理する(例外処理)

純粋な関数で似たようなことをするには?

function getAt(array, n) {
  if (n < 0 || n >= array.length) {
    return Error("Index out of bounds");
  }
  return array[n];
}

異常系の結果をまとめて処理する(例外処理)

使用例

result1 = getAt(array, 1);
if (result1 instanceof Error) {
  console.log("Error: " + result1.message);
} else {
  result2 = getAt(array, 2);
  if (result2 instanceof Error) {
    console.log("Error: " + result2.message);
  } else {
    // ...
  }
}

ここまでのまとめ

純粋な関数は、その制約により、

モナドとは

⚠️ あくまでもプログラミングの文脈での「モナド」の話です。
⚠️ 以下は定義ではありません。詳細は割愛します。Haskell などを学ぼう!

モナドがもたらすもの

実例、その前に

これまで使ってきた疑似言語にdo構文を導入します:

do {
  y <- f(x);
  a <- g(y, z);
  return a;
}

実例、その前に

これまで使ってきた疑似言語に do 構文を導入します:

State モナドで「結果を戻り値として返す以外で表現する」

👇以下のような関数は、State モナドの「命令」として使える:

function setNAtZeroPure(array, n) {
  //                    👆
  //                  arrayを受け取って
  result = array[0];
  newArray = set(array, n, 0);
  return [newArray, result];
  //      👆
  // またarray(引数と同じ型の値)をresultと一緒に返す
}

State モナドで「結果を戻り値として返す以外で表現する」

再掲: 純粋な関数だと面倒な例

array0  = [1, 2, 3];
[array1, result1] = setNAtZeroPure(array0, 0);
[array2, result2] = setNAtZeroPure(array1, 1);
[array3, result3] = setNAtZeroPure(array2, 2);

State モナドで「結果を戻り値として返す以外で表現する」

State モナドにおける)do 構文を使って書き換えると:

operations = do {
  result1 <- setNAtZeroPure(0);
  result2 <- setNAtZeroPure(1);
  result3 <- setNAtZeroPure(2);
}
operations([1, 2, 3]);

State モナドで「結果を戻り値として返す以外で表現する」

何が起きた?

// Before
[array1, result1] = setNAtZeroPure(array0, 0);

// After
result1 <- setNAtZeroPure(0);

State モナドで「結果を戻り値として返す以外で表現する」

array0 はどこに行った?

// Before
array0  = [1, 2, 3];

// After
operations = do { /* ... */ }
operations([1, 2, 3]);

State モナドで「結果を戻り値として返す以外で表現する」

do の中で ... <- f(x) という形で書かれた関数(命令)の呼び出しは、あたかも次のように見えるよう振る舞う:

  1. 暗黙の変数「状態」を表す引数を加える
  2. f を実行する
  3. 結果を「状態」の部分とそれ以外の部分(...)に分けて、
    1. 「状態」を更新しつつ、
    2. それ以外の部分を見える結果として返す

State モナドで「結果を戻り値として返す以外で表現する」

💡ポイント:

Either モナドで「異常系の結果をまとめて処理する」

🙇二重の意味で時間がないので詳細は割愛します😢

ここまでのまとめ

💔モナドが損なうもの

💔例: State モナドが損なうもの

do {
  foo <- doFoo(x, y);
  bar <- mutateBar();
  // ...
  // ... 何十行も続く ...
  // ...
  baz <- updateBaz(bar);
  // ... 更に続く ...
}

👿まだまだ損なうぞ!

🧐モナドを使うのは関数型プログラミングか?

🙄モナドを使うのは関数型プログラミングか?

関数型プログラミングとは純粋な関数を諦めるプログラミングだ

結局のところ関数型プログラミングは、

参考(本文中に言及がなかったもののみ)