YAMAMOTO Yuji (山本悠滋)
2026-07-11 関数型まつり 2026

Haskellを学んで以来、度々Haskellのモナドを解説してきました:
純粋な関数を中心としたプログラミングだ
(本発表における定義)
引数(入力)が同じであれば、常に同じ結果(出力)を返す関数
f が純粋な関数であれば、
x が同じであれば、必ず同じ結果を y
に代入するf は x 以外のどこからも影響を受けないf は y 以外のどこにも影響を与えない普通の関数: 引数の一部を直接書き換える
普通の関数: 引数の一部を直接書き換える
普通の関数: 引数の一部を直接書き換える
純粋な関数で似たようなことをするには?
使用例
array0 = [1, 2, 3];
[array1, result1] = setNAtZeroPure(array0, 0);
[array2, result2] = setNAtZeroPure(array1, 1);
[array3, result3] = setNAtZeroPure(array2, 2);普通の関数:
例外を投げることで、一箇所のcatchで処理する
使用例:
🙅♀️getAtは純粋?
純粋な関数で似たようなことをするには?
使用例
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 構文を導入します:
do { ... }:
result <- f(x):
f(x) を「命令」の実行として処理して、結果を
result に代入するdo
の中で「命令」を複数列挙すると、組み合わせることができるreturn a:
do
で組み合わせて作った「命令」の結果として、a を返すState
モナドで「結果を戻り値として返す以外で表現する」👇以下のような関数は、State
モナドの「命令」として使える:
State
モナドで「結果を戻り値として返す以外で表現する」再掲: 純粋な関数だと面倒な例
array0 = [1, 2, 3];
[array1, result1] = setNAtZeroPure(array0, 0);
[array2, result2] = setNAtZeroPure(array1, 1);
[array3, result3] = setNAtZeroPure(array2, 2);array0
などは直接書き換える
setNAtZeroPure に渡した後は、array0
などの値に関心がないはずState
モナドで「結果を戻り値として返す以外で表現する」(State モナドにおける)do
構文を使って書き換えると:
State
モナドで「結果を戻り値として返す以外で表現する」何が起きた?
array0 や array1 などが消えた!State
モナドで「結果を戻り値として返す以外で表現する」array0 はどこに行った?
do で組み立てた「命令」は、関数を返すState
モナドで「結果を戻り値として返す以外で表現する」do の中で ... <- f(x)
という形で書かれた関数(命令)の呼び出しは、あたかも次のように見えるよう振る舞う:
f を実行する...)に分けて、
State
モナドで「結果を戻り値として返す以外で表現する」💡ポイント:
do { ... }
で囲まれた範囲内でのみ「状態」を隠すdo { ... }
の結果として手に入る関数は、「状態」の初期値を引数として受け取る、純粋な関数となっている
do { ... } の外はやっぱり純粋な関数の世界Either モナドで「異常系の結果をまとめて処理する」🙇二重の意味で時間がないので詳細は割愛します😢
State モナドと同じように do { ... }
で囲われた範囲内で、例外処理っぽいことを実現してくれる!do { ... }
で囲まれた範囲内でのみ、モナドの種類ごとに決まったルールで、純粋な関数の制限を緩和してくれるdo { ... }
の中に留めてくれるため、純粋な関数の利点を損なわずに、普通の関数でできたことを再現できるdo { ... }
の中では純粋な関数の制限を緩和してくれるdo { ... } の中では純粋な関数の利点を損なうこともある
do { ... } の中身が大きくなった場合!State モナドが損なうものdo {
foo <- doFoo(x, y);
bar <- mutateBar();
// ...
// ... 何十行も続く ...
// ...
baz <- updateBaz(bar);
// ... 更に続く ...
}do の中に隠れている「状態」は updateBaz
の時点でどうなっている?State
モナドの「状態」はたかだか変数一つ分なのであまり困らないが…IO モナドがある
do { ... }
の外から見れば純粋な関数の性質を維持できるということは、結局のところ関数型プログラミングは、