プログラミング言語におけるモナドの擬人化1
あるいは,モナドのチュートリアル
モナドを頭だけではなく,心で理解する
関数型言語などでのプログラミングにおいて,「モナド」は重要で便利な概念(機構)ですが,圏論のイメージが強いのか,あるいは,高階の関数型言語が分かりにくいのか,モナドは,学習障壁が高く,なかなか分かりにくい概念です.
そこで,ここでは,現在流行りの AI の力を借りて,
文章と一緒に,人間のイメージに訴える絵を生成することで,少しでも
理解を助けることができるのでは無いかと思い,試してみました.
以下では,Google の AI モードに,
- モナドの簡単な説明をお願いし,また,
- 画像生成用のスクリプト作成もお願いして,
文章と画像の両方からモナドの理解を高めようと思います.尚,現時点 (2025.09.25)でGoogle のAI モードは画像生成まではできないみたいなので,画像生成は別の AI にお願いしました.
できるだけ分かりやすい説明を試みましたが,私の力不足で理解しにくいことも
あるかと思います.そのような場合でも,どうぞ,広い心をもってお許しください.
内容
AI への最初の依頼
関数型言語のモナドについて,
大学2年生を対象に,概要を教えるためのコンテンツを作ろうとしています.
モナドは大域変数への代入や IO など,不純(impure)な操作を,関数型言語の参照透明性を保ちながら模擬する(mimic)と言われます.
まずは,このイメージを学習者に持ってもらうために,モナドの絵を描こうと思います.画像生成AI がこの絵を描くためのスクリプトを 500文字くらいの自然語の文章で書いてください.
絵の内容はファンタジー風の絵で,モナドが扮するミミックが宝石箱の中で,プログラミングの冒険に出た人々を待ち構えているという絵にしてください.
AI の回答
以下は、関数型言語のモナドを、ファンタジー風のミミックに例えて表現する画像生成AI向けのスクリプトです。大学2年生がモナドの核心的なイメージを掴むことを目指しています。
スクリプト:
ファンタジー風の森の奥深く、苔むした岩が点在する場所に、豪華な金細工の宝石箱が置かれている。
蓋は半開きになっており、中からはきらめく宝石や金貨がこぼれ落ちそうだ。しかし、その宝石箱は実は「モナドのミミック」。中には鋭い牙と一つ目の大きな瞳を持つ魔物、ミミックが潜んでいる。
プログラミングの冒険者である若い魔法使いや剣士たちが、目を輝かせながら宝石箱に近づく。彼らが「不純な操作」(大域変数への代入、外部IOなど)という魔法を唱えようとすると、ミミックは舌なめずりしながら待ち構えている。
しかし、ミミックは箱の外には決して出ず、参照透明性という鎖で宝石箱に縛られている。冒険者たちは箱の周りを回り、中身を直接取り出そうとはしない。
代わりに、宝石箱のミミックと対話するように、ミミックの力を借りて安全に中身を操作する。ミミックは不純な操作を箱の中で代行し、結果を新しい宝石箱に詰めて冒険者たちに返す。
光と影のコントラストを際立たせ、冒険者たちの好奇心と、ミミックが持つ不穏な雰囲気を描き出す。宝石箱の内部は暗いが、中の宝石だけが妖しく輝いている。
私のコメント:
イメージを記述した文章なので,あまり期待していませんでしたが,次の下りは,かなり的確にモナドの特徴をとらえていると思います.つまり,データを箱の中に入れて,いったん,外界から遮断するんですね.
AIモードへの私の質問では,モナドは宝石箱に扮して,プログラマを襲おうとしている
イメージがあるように思うのですが,AIモードの回答は,モナドはプログラマを
不純な操作からプログラマを守っているように見えます.
しかし、ミミックは箱の外には決して出ず、参照透明性という鎖で宝石箱に縛られている。冒険者たちは箱の周りを回り、中身を直接取り出そうとはしない。代わりに、宝石箱のミミックと対話するように、ミミックの力を借りて安全に中身を操作する。ミミックは不純な操作を箱の中で代行し、結果を新しい宝石箱に詰めて冒険者たちに返す。
絵にしたらこんな感じですかね.本物の関数型言語にはミミックは出てきません.
要約:
ファンタジーの世界で、モナドを「不純な操作を箱の中で代行するミミック」として擬人化し、参照透明性を保ちながら冒険者(プログラマー)が安全に中身を操作する様子を描く。モナドの持つ不穏さと便利さを視覚的に表現する。
ミミック,あらため,モナドのイメージ
モナドのイメージ

モナドのイメージ

モナドのイメージ

モナドのイメージ
これは,リアルな写真に近いモードで生成しました.
少し,怖いかもです.
あと,ミミックが宝箱から出てます.

雰囲気は出てると思うのですが,モナドがうまく宝箱に偽装(mimic)しすぎていて
モナド自身の直接のイメージがつかみにくいかもしれないので,
私の最初の依頼の中から抜き出した次の短いスクリプトで画像生成してみました.
ファンタジー風の絵で,モナドが扮するミミックが宝石箱の中で,プログラミングの冒険に出た人々を待ち構えている
モナドのイメージ
左手が二本ありますが,mimic だから良いことにしましょうか.
モナドのイメージ

箱の中にいないで,箱から出てしまっているのですが,mimic って
こんな感じなんですかね.私もよく知りませんでした.
だいたい,
モナドのイメージは掴めたと思うのですが,やはり,絵だけでは
正確さに欠けるかもしれません.
そこで,ごく短くですが,文章でもモナドの説明をしておきます.
モナドの説明を読みたい場合は [ここをピックして展開して] ください
ここを開いてしまいましたね!
このまま読み進める場合は,開いたままで良いですが,
少し長いので,
後で読む場合は,
上の
「ここをピックして」のところをもう一度ピックすると
ここを隠すことができます.
では,始めます.
モナドは型構築子だと思ってください.例えば,C 言語で,いくつかの型の組み合わせの型(直積)を作る struct だったり,二つ以上の型の和集合の型を作る union だったりが型構築子の例です.この型構築子をどう使うのかは次に説明します.
実際のプログラミングでは数学の関数のように理論的にきれいにプログラムを記述できない場合が結構あります.例えば,関数 f として,int -> int の何らかの変換を記述する場合,結果が常にあるとは限りません.
プログラムの計算の途中で 0徐算みたいにエラーが起こるかもしれませんし,また,なかなか解が得られなくて,途中で諦めて計算を打ち切るかもしれません.
あるいは,プログラムの中で大域変数を参照したり,書き換えたりして,プログラム全体の挙動は,関数の表に出ているパラメータや結果の型だけでは決まらないことがあります.そういう場合は,例えば,先の f : int->int は,単純に値を返すだけではなく,その関数の中で変更した大域変数の値も組で返したいかもしれません.
一つ前の,計算の途中でエラーが起こるかもしれない場合の例に戻り,そういう場合があらかじめ想定されるときは f : int -> int の結果の型は,純粋に int ではなく,
int2 := int ∪ {Nothing}
というように拡張したデータ型にしたくなります.このint2 は,結果が int かもしれないし,Nothing かもしれないということで,Maybe int と書くことにしましょう.ここで,Maybe は,単なる記述の仕方だけでなく,int というデータ型,つまり,整数の集合に Nothing という値を加える型構築子と捉えることもできます.この型構築子がモナドです.
こうやって,計算の実情を反映させられる型を元の型 t から,Maybe t で簡単に作れるようになったら,そのような実際的なプログラムを作るために,Maybe t を返す関数をプログラミングしていけばよいのですが,一つ困ったことがあります.
それは,
- f : int -> Maybe int
- g : int -> Maybe int
・・・
と作っていっても,f や g を合成してつなげられないのです.例えば,合成関数
g∘f
を作ろうとしても,f の結果の型が Maybe int で,g が要求する型が int なので型が合わないのです.
もちろん,f も g も Maybe int -> Maybe int としてプログラミングしてしまえばよいのですが,面倒です.特に,各関数の入力部分は,「Nothing だったら,即,
Nothing を返して,そうでなかったら,具体的な計算に進んで,...」という
決まりきったパターンが多いのです.
そこで,モナドでは,型構築子に加えて,次の2つのテンプレートを用意します.
Maybe などのモナドを一般化して m と書くことにします.
モナドが組み込まれた関数型言語の代名詞ともいえる Haskell では,一般の型変数を使った多相型の関数を書けますので,別に関数のテンプレートを用意する必要はなく,普通の多相型関数を用意すれば良いです.
このように,型構築子と2つの関数のテンプレートを用意して,プログラムを
きれいに効率よく書いていくのが,モナドを使ったプログラミングです.
Maybe モナドは,モナドの考え方としては典型的なものでしたが,複雑さという点ではかなり簡単なものでした.したがって,一般のモナドを理解するのは,
やはり,努力がいると思います.特に,高階の関数を多用しますので,それに
慣れる必要があります.
関数型言語では,モナドは,副作用のない書き方なのだけど,大域変数相当をすべての関数に引き回すスタイルでなく,手続き型言語に近い形で書けるようにする目的で提供されているものが多いように思います.
先ほど述べた大域変数を関数内で参照・更新する例ですが,これは,大域変数を
やめて,その代わりに,その大域変数が保持する値を関数の引数と結果に
含ませれば,副作用のないプログラムができます.でも,これは,引数が
沢山になって,見にくいし,書きにくいのです.これを,引き回す変数を明示的に
書かないスタイルで,かつ,副作用を起こさないで行う State モナド, Reader モナド,Writer モナドといったモナドもあります.これらは,高階の関数を
使うので,少し分かりにくく,慣れがいるかもしれません.
Haskell では,IO モナドも副作用がないことになっています.私は,これについては,モナドだけでそれが達成されているのではなく,レトリックがあるような感じを受けます.「こういう形態は副作用が無いと認識するのだ」というレトリックです.
もっとも,レトリックとは,たぶん,言いくるめることではなく,正しい認識に到達する議論上の手法という捉え方もあると思いますので,そこを真に理解すれば,
Haskell の IO には副作用が無いという認識に到達できるのだと思います.
ここでは,モナドの基本的な考え方を説明しましたので,後は,もう少し,しっかりした読み物やマニュアルなどを参考にしながら学習されたら良いと思います.また,自分で,モナドを考えたり,Haskell 以外の言語に導入してみたりというのも役に立つと思います.
関数型言語のモナドは,Eugenio Moggi が,プログラムの意味論の研究で,圏論のモナドから着想を得て提案し,それを
Philip Wadler や Simon Peyton Jones が,Haskell に取り入れたものです.
皆さんの中には,その圏論とのつながりから勉強したいと思う人もいるかもしれませんが,もし,皆さんが圏論の初心者なら,モナドから入るのではなく,それと同等の概念のクライスリトリプル,あるいは,クライスリ圏から入った方が良いです.
Moggi の着想は,かなり素朴で分かりやすいものです.それと直接対応しているのは,クライスリトリプルやクライスリ圏です.圏があまり分かっていない場合,モナドから入ると,方向を見失ってしまいがちです.
おまけ画像
女神様は二人生成して,もう一方をオープニングに使いましたので,残りももったいないのでここに入れておきます.
ここの内容を読みたい場合は上の「ピックして展開して」をマウスでピックしてください.
以上が,モナドの一般的な説明でしたが,モナドは用途に合わせていろいろなモナドが提案されています.また,Haskell などでは,ユーザが作ることもできます.
ここでは,よく使われるモナドとして,
- Maybe
- Either
- List
- IO
- State
- Reader(Environment)
- Writer
- Continuation
のそれぞれについて,概要とイメージを AI に書いてもらいたいと思います.
AI へのモナドの概要説明と画像生成用スクリプト作成の依頼
モナドの一般的なイメージは分かりました.では,主要なモナドとして
Maybe, Either, List, IO, State, Reader(Environment), Writer, Continuation
について,概要と...(ここは秘密)...画像生成用のスクリプトをそれぞれ500文字程度で書いてください.擬人化においてはその特徴がよく分かるように,かつ,楽しいものにしてください.
- Maybe モナド
概要
Maybeモナドは、計算が成功して値を持つ場合(Just a)と、失敗して値を持たない場合(Nothing)を表現するモナドです。複数の失敗しうる計算を安全につなげることができ、途中で失敗した場合はそれ以降の計算をスキップし、最終結果をNothingとします。これにより、nullポインタ例外のような問題を防ぎ、エラーハンドリングを簡潔にします。
擬人化スクリプト
カフェの優雅なウェイトレス、名前は「メイ」。
彼女の仕事は、注文された飲み物をテーブルに運ぶこと。メイのトレイにはいつも、完璧なコーヒーが入ったカップ(Just a)が乗っている。しかし、時々、何かの拍子でカップが空になってしまうことがある。そんな時、彼女は笑顔で空のトレイ(Nothing)を運んでくる。
メイのすごいところは、空のトレイを渡された後、次の注文を尋ねないこと。彼女は静かに失敗を知らせ、次の指示を待つ。メイの周りには、彼女のふるまいを安全に予測して次のアクションを決める常連客たち(プログラマー)が集っている。彼女の制服は、一方はコーヒー色、もう一方は透明なグラデーションになっている。
注) 擬人化スクリプトは,予想以上に良くできた,Maybe モナドの内容を良く表現したスクリプトだと思いました.これを読むだけで,結構役に立つと思います.
Maybe モナド

Maybe モナド

Maybe モナド

- Either モナド
概要
Eitherモナドは、Maybeモナドの拡張版です。成功と失敗の2つの可能性を表しますが、失敗した場合にエラー情報を保持できる点が異なります。一般的に、成功はRightに値が入り、失敗はLeftにエラー情報が入ります。これにより、失敗した理由まで含めてハンドリングできます。
擬人化スクリプト
街の運送業者「イーサ」は、2つの顔を持つ双子の姉妹だ。
成功担当の明るい「ライト」は、価値ある荷物(Right a)を笑顔で届ける。一方、失敗担当の冷静な「レフト」は、壊れてしまった荷物や、配達できなかった理由を書いた手紙(Left e)を渡す。
イーサは、どの計算(配達)がうまくいき、どの計算が失敗したのか、そしてその理由(エラー情報)を明確に記録する。二人の姉妹はいつも背中合わせで行動し、一つの運搬作業(計算)の結果を二人で担当する。彼女たちの周りには、ライトから荷物を受け取る人、レフトから手紙を受け取る人がおり、イーサの配達結果に合わせて次に何をすべきか決めている。
Either モナド

Either モナド

Either モナド

- List モナド
概要
Listモナドは、「複数の可能性のある結果」を表現するモナドです。複数の計算をつなげる際、それぞれの計算が複数の結果を返す場合、全ての組み合わせを生成します。これは、非決定性計算やバックトラックを要するアルゴリズムを簡潔に記述するのに役立ちます。
擬人化スクリプト
広大な図書館を管理する司書の「リサ」。
彼女は、探している本(計算の結果)が複数存在する場合、全ての該当する本を抜き出して持ってくる。リサが持ってくるのは、一冊ではなく、探している本の全てのバージョン、全ての版、全ての作者の本が詰まったカート(リスト)だ。さらに、彼女は新しい本を見つけるたびに、カートの数を増やしていく。
彼女の周りは、本を探している冒険者たちでいっぱいだ。彼らは、リサが持ってきた本の山から、目的のものを探し出す。リサの髪型は、まるで本棚のように幾重にも重なっており、その中にはたくさんの秘密が隠されている。
List モナド

List モナド

List モナド

- IO モナド
概要
IOモナドは、ファイル入出力や画面表示など、参照透過性を損なう可能性のある副作用を持つ操作を安全に扱うためのモナドです。IOモナドは、プログラムが実行すべき一連の「手続き」を表現し、その手続きが実際に実行されるまで副作用を閉じ込めます。
擬人化スクリプト
舞台裏で全てのセットチェンジや効果音を操る、影の演出家「イオ」。
彼女は舞台上(プログラムの実行)に直接姿を現すことはなく、指示書(IOアクション)を通じて全ての操作を行う。イオの指示書には、「このタイミングで照明を当てる」「あのタイミングで観客からの入力を受け付ける」といった、舞台に影響を与える操作が書かれている。
演者たち(純粋な関数)はイオの指示書に書かれた通りに動き、イオが舞台裏で操ることで、舞台上では一貫したパフォーマンスが保たれる。彼女の衣装は、背景に溶け込むような黒いマントだが、手に持った指示書だけが光を放っている。
io モナド

io モナド

io モナド

- State モナド
概要
Stateモナドは、状態(グローバル変数のようなもの)を伴う計算を、参照透過性を保ちながら記述するためのモナドです。関数は状態を受け取り、新しい状態と結果のペアを返します。これにより、グローバルな状態を明示的に受け渡すことなく、状態を更新しながら計算を進めることができます。
擬人化スクリプト
記憶力抜群の天才数学者「ステイシー」。
彼女は、計算を行うたびに、頭の中の黒板(状態)を更新する。ステイシーは、計算式(関数)を受け取ると、黒板の内容(古い状態)を見て計算を行い、その結果と、更新された黒板の内容(新しい状態)をペアで返す。
彼女の周りの生徒たちは、ステイシーの完璧な記憶力と、常に最新の状態を保つ能力に感心している。ステイシーは、まるで魔法のように計算を進めるが、その内側では厳密な状態の受け渡しが行われている。彼女の服は、白衣にたくさんの数式や計算結果が書き込まれており、常に最新の「状態」を反映している。
state モナド

state モナド

state モナド

- Reader(Environment) モナド
概要
Readerモナドは、読み取り専用の共有環境(設定ファイルやデータベース接続など)を扱うためのモナドです。複数の計算が、同じ環境を共有しながら実行される場合に便利です。Stateモナドと異なり、環境は更新されません。
擬人化スクリプト
王国の歴史を全て記憶し、誰にでも教えることができる賢者「リア」。
彼女は、質問(関数)を受けると、王国の歴史書(環境)を参照し、答えを教える。
リアのすごいところは、歴史書は絶対に書き換えられないため、彼女が教える知識は常に一貫していることだ。リアは、王国に存在するすべての知識を読み取る能力を持っているが、彼女自身がその歴史を変えることは決してない。彼女の周りには、様々な情報を求めて質問する人々が集まっている。彼女の服は、古くからの書物のような重厚なデザインで、杖には叡智を象徴する水晶が輝いている。
reader モナド

reader モナド

reader モナド

- Writer モナド
概要
Writerモナドは、計算を行いながらログやトレース情報といった「追加情報」を蓄積していくためのモナドです。計算の最終的な結果だけでなく、その計算過程で何が起こったかを記録したい場合に適しています。
擬人化スクリプト
計算を行うと同時に、その過程を全てメモする記録係の「ライター」。
彼女は、計算(関数)を受け取ると、その結果だけでなく、「この値を足しました」「この条件分岐を通りました」といったメモ(ログ)をノートに書き留める。ライターは、計算が進むたびに、新しいメモをこれまでのメモの末尾に足していく。
彼女の周りには、計算結果だけでなく、その過程を知りたい人々が集まっている。ライターは、計算が進むたびにノートを広げ、次のページに書き加えていく。彼女の衣装は、たくさんのメモやペンが刺さった、ちょっと散らかった事務服だ。
writer モナド

writer モナド

writer モナド

- Continuation モナド
概要
Continuationモナドは、プログラムの「残り全ての計算」(継続)を抽象化する、強力で複雑なモナドです。これを用いると、通常の関数の流れを制御し、特定の時点に戻ったり、例外のような処理を行ったりできます。
擬人化スクリプト
時間と空間を操る魔女「コンティナ」。
彼女は、今行われている計算の「続き」を全て捕まえて、魔法の壺(継続)に閉じ込める。コンティナは、その壺を自由に使って、時間を巻き戻したり、未来の計算をスキップしたりできる。彼女の魔法は強力で、通常の計算の流れを完全に書き換えてしまう。
彼女の周りには、コンティナの魔法を恐れつつも、その力を利用して複雑な問題を解決しようとする探求者たちがいる。彼女の服は、時間の流れを象徴する渦巻き模様で、指先からは計算の「続き」が光の糸のように伸びている。
Continuation モナド

Continuation モナド

Continuation モナド

ここでのモナドの説明はこれで終わりですが,ほんの少しでも,皆様の理解の助けになれば幸いです.
モナドの考え方さえ分かってしまえば,後は,Wikipedia を見たり,Haskell のマニュアルに当たってみたり,その他,解説を読んだりすれば良いと思います.
ここでは,
画像生成 AI には,https://perchance.org/ai-girl-image-generator を使いました.
先頭に戻る
AI画像生成を使った遊び in 計算機科学へ
ホームページトップへ