この記事はモナド(プログラミング)の一部として作成された内容を元にしています。
IOモナドとは、モナドの一種である。特に画面出力すら状態変更として禁止しようとするHaskellでは、入出力を実現するために用いられる。
イミュータブルを原則とする関数型プログラミングでは、画面表示ですら状態変更(副作用)の禁忌に含まれる。しかしIOモナドは、現実世界への入出力という副作用を参照透過性を保ったまま実現できるという一見矛盾した存在である。
たいていのIOモナドの説明は、以下のような感じである。
さすがに上記ではあんまりなので、もう少しましな説明をすると、IOモナドというのは一種のStateモナド(あるいはSTモナド)で、このStateに該当するのが現実世界そのものであり、表記上は省略されている。
そしてIOモナドの中に格納されているものはStateモナド同様関数であり、その関数はなんと現実世界を引数として受け取って、所定の状態変更がなされた後の現実世界を値として返すのである。つまり、IOモナドの中では常に世界は新しく作りなおされているんだよ!
Ω ΩΩ < ナ ナンダッテー!!
お前は何を言っているんだと思った方も多いであろう。しかし、実際にHaskellのデファクトスタンダードであるGHCにおいてIOモナドは定義内部に"RealWorld"という値を持って実装されている。
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
関数型プログラミングにおいて関数は数値や文字列と同様にイミュータブルな「値」であるという事実を思い出せば、「画面に文字を表示する」という「副作用」も、「画面(世界)を引数に取り、文字が表示された画面(世界)を戻り値として返す関数」という参照透過な「値」に変換できることがわかる。
これはIOモナド(の元であるStateモナド)固有の性質により実現されているのであって、一般的なモナドの性質で実現されているわけではない。モナドの一般的な性質により実現されているのは、「Aを出力する」と「Bを出力する」を連結して「Aを出力してからBを出力する」にできるという部分である。
IOモナド固有の性質とモナド一般の性質をはっきり分けずに、「IOモナドで副作用を伴わずに画面変更を実現できました。モナドすごい。」みたいな説明をしてしまうことが混乱の元になっている。
誤: Haskellではモナドの性質により参照透過性を保ったまま副作用を実現している。
正: Haskellでは入出力は現実世界を引数と戻り値にとる関数と考えることで、参照透過性を保ったまま(入出力という)副作用を実現している。さらにそれをIOモナドとすることで、モナドの性質により入出力を連結可能にしている。
鋭い読者は気づいただろうか? IOモナドがStateモナドの「状態」の部分にRealWorldが入ったものだとすると、
IO x = λ RealWorld → (x, p(RealWorld))
というということになるが、この x は何だろう?
IOモナドだということを思い出してほしい。つまり、この x は Input: 入力を表すのである。
IOモナドは、現実世界を引数として受け取り、現実世界からの入力内容と、入力後の現実世界を戻り値として返す関数でもあるのだ。
IOモナドの中にRealWorldがあることを知っていると、下記はそれにちなんだ名前なのかもと思いたくなるが、Real World〜とつく本は同出版社から複数出ているので、単なるシリーズ名のようだ。
掲示板
5 ななしのよっしん
2025/01/21(火) 20:55:16 ID: TYqJFuABi+
>>違います
ランタイムレベルで副作用が発生しているということに変わりないのでは?
バインド(>>=)はあくまで副作用の発生順序を縛っているだけで、副作用をランタイムレベルに押し込んでいるのは設計のたまものだし、副作用がバインド(>>=)に集約されるというのはなんか夢見すぎだと思う。
6 ななしのよっしん
2025/06/04(水) 18:22:53 ID: mR1gN3Rbp9
そもそもモナドと副作用は関係ありません。
「モナドが副作用を実現している」というのは、FizzBuzzのコードを見て
「if文は剰余を計算している」「for文は文字列をプリントしている」
などと言っているようなもの。甚だしい勘違いです。
正直、>>4のような人とは議論をする価値がないです。
この話は、圏・関手・自然変換などの厳密な定義、Haskellの言語仕様や処理系の実装に関する正確な理解が不可欠です。
彼のような人は、
・公式の仕様書などの一次資料を読まない
・読んでも理解できない
(省略しています。全て読むにはこのリンクをクリック!)
7 deadbull
2025/06/07(土) 06:18:12 ID: yJma91Iq12
>>6
>>4を当方と勘違いしておられるようなので、少しだけコメントすると
>モナドと副作用はなんの関係もありません。
モナド全体が副作用と関係ある訳ではないことについて>>3と当記事に意見の相違はないように思います。
記事にも書いてあるように副作用と関係するのはモナド一般ではなくIOモナドであり、さらに言えば>>4が言うようにHaskellのランタイムにおけるIOモナドの実装に内在するRealWorldです。
一方で、>>5の>>4に対する
> バインド(>>=)はあくまで副作用の発生順序を縛っているだけ
という指摘はあっていると思います。
急上昇ワード改
最終更新:2025/12/24(水) 00:00
最終更新:2025/12/23(火) 23:00
ウォッチリストに追加しました!
すでにウォッチリストに
入っています。
追加に失敗しました。
ほめた!
ほめるを取消しました。
ほめるに失敗しました。
ほめるの取消しに失敗しました。