他のモナドのように IO モナドをエスケープすることはできません
「逃げる」という言葉の意味がわかりません。つまり、どうにかしてモナド値の内部表現をアンラップします (例: リスト -> コンスセルのシーケンス)。これは実装の詳細です。実際、純粋な HaskellでIO
エミュレーションを定義できます。基本的にはState
、グローバルに利用可能なデータが大量にあるだけです。それは のすべてのセマンティクスを持ちますがIO
、現実世界と実際にやり取りすることなく、そのシミュレーションのみを行います。
つまり、モナド内から「値を抽出」することができます – いや、ほとんどの純粋な Haskell モナドでさえ、それは一般的に可能ではありません。たとえば、Maybe a
(could be Nothing
) またはReader b a
(what if b
is uninhabited?)から値を抽出することはできません。
IO
main
アクションは関数によってのみ実行できます
まあ、ある意味では、すべては関数によってのみ実行できmain
ます。何らかの方法で呼び出されないコードはそこにあるだけで、何も変更せずにmain
置き換えることができます。undefined
IO は常にモナド トランスフォーマー チェーンの一番下にあります
本当ですが、それは例えばの場合にも当てはまりST
ます。
IO
モナドの実装は不明確で、ソースコードには Haskell の内部構造がいくつか示されています
繰り返しますが、実装は実装の詳細です。実装の複雑さはIO
、実際には高度に最適化されていることに大きく関係しています。特殊化された純粋なモナド (たとえばattoparsec )についても同じことが言えます。
すでに述べたように)、より単純な実装が可能ですが、それらは完全に最適化された現実世界のIO
型ほど有用ではありません。
幸いなことに、実装はそれほど気にする必要はありません。の内部はIO
不明確かもしれませんが、実際のモナド インターフェイスである外部は非常に単純です。
純粋なコードの評価順序は関係ありません
まず第一に、純粋なコードでは評価順序が重要になる可能性があります!
Prelude> take 10 $ foldr (\h t -> h `seq` (h:t)) [] [0..]
[0,1,2,3,4,5,6,7,8,9]
Prelude> take 10 $ foldr (\h t -> t `seq` (h:t)) [] [0..]
^CInterrupted.
しかし実際には、純粋なコードの評価の順序が間違っているために、 ⊥ 以外の誤った結果が得られることは決してありません。ただし、実際にはモナド アクションの並べ替え (またはその他) には適用されません。IO
シーケンスの順序を変更すると、ランタイムがこの構造を構築するために使用する評価順序だけでなく、結果のアクションの実際の構造も変更されるためです。
例 (リストモナド):
Prelude> [1,2,3] >>= \e -> [10,20,30] >>= \z -> [e+z]
[11,21,31,12,22,32,13,23,33]
Prelude> [10,20,30] >>= \z -> [1,2,3] >>= \e -> [e+z]
[11,12,13,21,22,23,31,32,33]
そうは言っても、確かに非常に特別です。実際、モナドと呼ぶのをためらう人もいると思います(モナドの法則を満たすためIO
に実際に何を意味するのかは少し不明です)。IO
特に、レイジー IOは大きなトラブルメーカーの 1 つです (常に避けるのが最善です)。