これは、IO
モナドの「解釈」として提案されています。この「解釈」を真剣に受け止めたい場合は、「RealWorld」を真剣に受け止める必要があります。action world
投機的に評価されるかどうか、action
副作用がないかどうかは関係ありません。その影響は、ネットワークパケットが送信されたなど、それらの影響が発生したユニバースの新しい状態を返すことによって処理されます。ただし、関数の結果((),world)
はworld
です。したがって、宇宙の新しい状態はです。側で投機的に評価したかもしれない新しい宇宙を使用しません。宇宙の状態はworld
です。
あなたはおそらくそれを真剣に考えるのに苦労しています。これはせいぜい表面的に逆説的で無意味な多くの方法があります。この観点では、同時実行性は特に非自明または狂気のどちらかです。
「待って、待って」とあなたは言う。「RealWorld
単なる「トークン」です。実際には、宇宙全体の状態ではありません。」さて、この「解釈」は何も説明しません。それでも、実装の詳細として、これはGHCがモデル化する方法IO
です。1ただし、これは、実際には副作用がある魔法の「機能」があることを意味し、このモデルはそれらの意味に対するガイダンスを提供しません。また、これらの関数には実際に副作用があるため、提起する懸念は完全に適切です。GHC は確実に邪魔にならないようにしなければならずRealWorld
、これらの特別な機能は、プログラムの意図された動作を変更する方法で最適化されていません。
個人的には(おそらく今では明らかなように)、この「世界を通過する」モデルはIO
、教育ツールとしては役に立たず、混乱を招くと思います。(実装に役立つかどうかはわかりません。GHCの場合、これはより歴史的な成果物だと思います。)
別のアプローチの1つはIO
、応答ハンドラーを使用して要求を説明するものと見なすことです。これを行うにはいくつかの方法があります。おそらく最もアクセスしやすいのは、無料のモナド構造を使用することです。具体的には、次のものを使用できます。
data IO a = Return a | Request OSRequest (OSResponse -> IO a)
これをより洗練されたプロパティにするための多くの方法がありますが、これはすでに改善されています。理解するために、現実の性質についての深い哲学的仮定を必要としません。それが述べているのIO
はReturn
、値を返す以外の何もしない単純なプログラムであるか、または応答のハンドラーを使用したオペレーティングシステムへの要求であるということだけです。OSRequest
次のようになります:
data OSRequest = OpenFile FilePath | PutStr String | ...
同様に、OSResponse
次のようになります。
data OSResponse = Errno Int | OpenSucceeded Handle | ...
(可能な改良点の1つは、リクエストOpenSucceeded
から取得しないことを確認できるように、よりタイプセーフにすることですPutStr
。)このモデルIO
は、何らかのシステムによって解釈されるリクエストを記述するものとしてモデル化されます(「実際の」IO
モナドHaskellランタイム自体)、そしておそらく、そのシステムは、応答を提供したハンドラーを呼び出します。もちろん、これはリクエストのPutStr "hello world"
処理方法を示すものではありませんが、ふりをするわけでもありません。これが他のシステムに委任されていることを明示します。このモデルもかなり正確です。最新のOSのすべてのユーザープログラムは、OSに何かを要求する必要があります。
このモデルは正しい直観を提供します。例えば、多くの初心者はのようなものを表示<-
「アンラップ」としてオペレータをIO
、またはこと(残念ながら強化)景色を眺めることができIO String
、たとえば、「含まれている」ことを「コンテナ」であるString
S(そして<-
それらを取得します)。この要求/応答ビューは、この観点を明らかに間違っています。内にファイルハンドルはありませんOpenFile "foo" (\r -> ...)
。これを強調する一般的な例えは、ケーキのレシピの中にケーキがないことです(または、この場合は「請求書」が良いでしょう)。
このモデルは、並行性でも容易に機能します。OSRequest
likeのコンストラクターを簡単に作成Fork :: (OSResponse -> IO ()) -> OSRequest
でき、ランタイムはこの追加ハンドラーによって生成された要求を通常のハンドラーとインターリーブできます。ある程度の賢明さで、この(または関連する手法)を使用して、「OSにリクエストを送信し、物事が発生する」だけでなく、並行性などをより直接モデル化できます。これがIOSpec
ライブラリの仕組みです。
1 Hugsは継続ベースの実装を使用しましたが、IO
その実装は、明示的なデータ型ではなく不透明な関数を使用して説明したものとほぼ同じです。HBCは、古いリクエスト/レスポンスストリームベースのIOの上に階層化された継続ベースの実装も使用しました。NHC(したがってYHC)はサンクを使用しました。つまり、大まかに呼ばれてIO a = () -> a
いました()
がWorld
、状態の受け渡しはしていません。JHCとUHCは基本的にGHCと同じアプローチを使用しました。