web-dev-qa-db-ja.com

IORefを使用してもよいのはいつですか?

いつも私を混乱させてきたのは、IORefを使用するのに問題がないかどうかです。タスクにIORefを使用するかどうかを決定する際に従う必要のあるガイドラインはありますか? IORef上でStateモナドを使用するのに適した時期はいつですか?

60
Rayne

ステートとその相対STはどちらも、ユニットとして実行できる「モノリシック」ステートフル計算を生成します。それらは基本的に、結果を生成するために必要な中間データとして可変状態を扱いますが、それ自体では、プログラムの他の部分には関心がないはずです。

一方、IORef内に配置するのは、実行される「計算」ではありません。これは、IO内でかなり任意の方法で使用できる単純な値を保持するボックスです。 。このボックスは、データ構造内に配置したり、プログラム(のIO部分)に渡したり、都合のよいときに内容を置き換えたり、関数などで閉じたりすることができます。実際、変数の厄介な性質の多くはまた、Cのような言語のポインターはIORefでモデル化でき、どの言語でもCコードを記述できるという評判を維持したいエキスパートCプログラマーに大きな支援を提供します...これは間違いなく注意して使用する必要があります。

それでも、1つのコードブロックで可変状態の一部とのすべての相互作用を分離することは、まったく不可能ではないにしても、時には非常に扱いにくいです-一部の状態は、単に渡されたり、データ構造内に配置されたりする必要があります。そのような場合、ボックスアプローチが唯一のオプションである可能性があります。 可変状態を紹介する章 「48時間でSchemeを書く」チュートリアル(ちなみに、強くお勧めします)に例があります。 (Schemeインタープリターの特定の設計でSch​​eme環境をモデル化するために、StateやSTではなくIORefを使用することが本当に最も適切である理由についての素晴らしい議論については、リンクを参照してください。)

つまり、これらの環境は任意の方法でネストし、ユーザーインタラクションのインスタンス間で維持する必要があります((define x 1)スキームで入力REPLは、ユーザーが後でxを入力し、値として1を返すことができるようになるはずです)、オブジェクトモデリングスキーム関数( Scheme関数は、それらが作成された環境上で閉じるため)など。

要約すると、タスクがそれに適していると思われる場合、州は最もクリーンなソリューションを提供する傾向があると思います。複数の個別の状態が必要な場合は、おそらくSTが役立ちます。ただし、ステートフル計算が扱いにくいか、独自のコードに固定できない場合は、複雑なプログラムなどの寿命の大部分で状態を変更可能な形式で保持する必要があります。IORefは単なる適切なこと。

繰り返しになりますが、IOコードによって制御された方法で渡され、相互作用する可能性のある一種の可変状態が必要な場合は、STMとそのTVarをチェックしてみませんか?実際、並行性の存在は、someの並行性関連タスクの解決を実際に単純にするほどです。これは、質問とはあまり関係がありません。 、しかし、私は詳しく説明するように促すことに抵抗します。:-)

73
Michał Marczyk

うーん。変更可能な状態が必要であるが、シングルスレッド環境にある場合は、IORefを使用します。または、同期変数によって保持される、より大きな構造内の可変フィールドが必要な場合。

一般に、MVarを使用します。それらはより堅牢なセマンティクスを持っています。

14
Don Stewart

個人的には、そしてすでにIORefを使用している場合にのみ、IOsを使用しても問題ないと思います。それ以外の場合は、Stateの優れたパフォーマンスが必要でない限り、常にSTです。いくつかのヘルパー関数を使用して、Stateモナドで状態の複数のスレッドを使用することができます。状態をタプルまたはレコードにし、各フィールドを個別に設定、取得、または更新する関数を定義するだけです。

特に、通常、_StateT s IO_を使用する意味はあまりありません。すでにIOにいる場合は、すでに可変状態になっているので、たとえばReaderT (IORef s) IOを使用することをお勧めします。

3
Ben Millwood

状態がローカライズされており、環境との対話を必要としない場合は、STRefを使用します。

1
newacct