GHC 以外の処理系での IO 型/IO モナドの実装

Haskell での IO 型/IO モナドの実装としては、現在 GHC で使われている World を状態として受け渡すやり方が有名です。ですが、GHC での実装が IO 型/IO モナドを定義するための唯一の方法というわけではありません。他の処理系では、GHC とはまた違った方法で IO 型/IO モナドの実装を行っています。(中には GHC と同じ方法を採用しているものもありますが。)というわけで、他の処理系での IO 型/IO モナドの実装についてまとめました。
プログラミング Monad Haskell モナド
4151view 0コメント
10
How to declare an imperative
shelarcy(しぇらーしぃ) @shelarcy
@ranha あっ、それは大丈夫です。"How to declare an imperative" が IO モナドを実装するのに、無限リスト、継続、線形論理(World という状態の引渡し)の三つを使っているので、List モナドを引き合いに出してみただけです。
Hugs での IO 型/IO モナドの定義
shelarcy(しぇらーしぃ) @shelarcy
これを読んで、色んな処理系での IO 型や IO モナドの定義を見てみると楽しいですよ。例えば、Hugs の IO モナドの定義は prim* 関数を使ってあんまり参考にならないのですが、IO 型の定義を見てみると継続渡し形式(CPS)で実装されていることが分かります。
shelarcy(しぇらーしぃ) @shelarcy
Hugs での IO 型の定義: newtype IO a = IO ((a -> IOResult) -> IOResult)
shelarcy(しぇらーしぃ) @shelarcy
data IOResult = Hugs_ExitWith Int | Hugs_Catch IOResult (Exception -> IOResult) (Obj -> IOResult) ~略~ | Hugs_Return Obj ~略~
shelarcy(しぇらーしぃ) @shelarcy
Hugs の IO 型の完全な定義を知りたければ、こちらのソースコードを http://bit.ly/3kMlqp prim* 関数の定義を知りたければこちらの C のソースコードを http://bit.ly/1fwfBC 見てください。

Hugs のソースコードから Hugs での IO 型の定義を抜き出したものを codepad に置いておきました。 http://codepad.org/o8Nr5Tbw

HBC/HBI での IO 型/IO モナドの定義
shelarcy(しぇらーしぃ) @shelarcy
@ranha あと、ちゃんと議論したいなら、Dialogue model (無限リスト)の上に I/O モナドを構築している HBC/HBI の実装も見た方が良いと思います。http://bit.ly/2c6j58
shelarcy(しぇらーしぃ) @shelarcy
というわけで、議論の前提にできるよう codepad に HBC/HBI の I/O モナド実装部分のソースコードを張ってみました。http://codepad.org/3SbnpA2x 勘違いがあれば、どなたか訂正してください。
NHC での IO 型/IO モナドの実装

newtype IO a = IO (World -> Either IOError a)

IO 型の表現では、引数の方には World がでてきますが、返値には World は出てきません。World を状態として扱わずに、組み込みの prim* 関数などの引数/返値にしています。

またもう一つ特徴的なのが、I/O エラー(例外)を扱うために Either 型を使って IO 型を表現しているところです。

c.f. http://darcs.haskell.org/nhc98/src/prelude/Internal/Internal.hs http://darcs.haskell.org/nhc98/src/prelude/PreludeIO/Monad_IO.hs http://darcs.haskell.org/nhc98/src/prelude/PreludeIO/DIOError.hs http://darcs.haskell.org/nhc98/src/prelude/PreludeIO/Catch.hs

YHC での IO 型/IO モナドの実装

newtype IO a = IO (World -> _E a)

NHC の fork である YHC でも World を状態として扱わない表現となっています。

ただし、NHC と違い _E 型は例外を表現するためのものではありません。_E 型は forkIO 関数を使った並行処理のために使われます。

shelarcy(しぇらーしぃ) @shelarcy
YHC の IO 型では、World を状態扱いしないため、forkIO で作ったスレッドの親スレッドでの評価を防ぐために _E 型を使っているそうです。代わりに catch 関数の定義に正格評価とか出てきて面白いですね。 http://t.co/3mkFqRW9
JHC/UHC での IO 型/IO モナドの定義

JHC や現在の UHC の IO 型/IO モナドの実装は、GHC と同じく (Real)World を状態として受け渡す形になっています。

このように IO 型や IO モナドの実装自体は変わらないのですが、JHC では IO 型や IO モナドの機能を拡張するための型が二つ提供されています。

一つは、JHC.ACIO モジュールで提供されている ACIO(Affine Central IO)型です。JHC には、ACIO 型を使うことでモジュールのトップレベルでアクションを実行できる、という拡張機能が提供されています。 http://repetae.net/dw/darcsweb.cgi?r=jhc;a=headblob;f=/lib/jhc/Jhc/ACIO.hs

もう一つは、System.IO.Continuation モジュールで提供されている IOCont 型です。こちらは、I/O アクションで継続(jump)を使った処理を行えるようにするためのものです。 http://repetae.net/dw/darcsweb.cgi?r=jhc;a=headblob;f=/lib/base/System/IO/Continuation.hs

ログインして広告を非表示にする
ログインして広告を非表示にする