この記事はモナド(プログラミング)の一部として作成された内容を元にしています。
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〜とつく本は同出版社から複数出ているので、単なるシリーズ名のようだ。
掲示板
1 ◆CBGbQXRNEo
2022/09/16(金) 10:52:59 ID: adnwAMCbol
2 ななしのよっしん
2023/03/09(木) 11:31:55 ID: m8pSrWPxr7
関数側は敵対的コピーに変更を掛けていることにして、副作用の責任をさも呼び出した側にあるように見せかけている
考えた奴は保険屋向いてると思う←悪口
3 ななしのよっしん
2023/09/30(土) 21:45:12 ID: mR1gN3Rbp9
もういい加減に、こういう嘘の内容のポエムを量産するのやめませんか。
アクションを読み取ると副作用を起こすのは、Haskellのランタイムの機能であり、モナドと副作用はなんの関係もありません。
急上昇ワード改
最終更新:2024/12/02(月) 05:00
最終更新:2024/12/02(月) 05:00
ウォッチリストに追加しました!
すでにウォッチリストに
入っています。
追加に失敗しました。
ほめた!
ほめるを取消しました。
ほめるに失敗しました。
ほめるの取消しに失敗しました。