どういったときに IORef を使うべきか
どういったときに IORef を使うべきか、という疑問が湧いてきたので、ぐぐってみると stackoverflow に同じ質問してる人がいたのでそれを訳してみる(2009年のものだから情報古いかも)。
"いつ IORef を使うべきか混乱しています。 IORef を使うべきか否かを判断するとき、従うべきガイドラインはありますか? どのような状況なら、IORef でなくて State モナドを用いるべきなのでしょうか。"
以下がこの質問に対しての返答です。
" State やそれに関連した ST は、どれもユニットとしてのモノリシックな状態を持つ計算を生成します。これらは、ふつう書き換え可能な状態を一時的なデータとして扱います。つまり、結果を得るために必要なものですが、使ったあとは気にする必要がない(というよりすべき得ない)ということです。
一方で、 IORef に入れるモノは"計算"ではありません。 IORef は IO 内で自由に使える値を保持できるただの箱に過ぎません。この箱はデータ構造も入れられますし、( IO 部分の)プログラムの中で自由に渡せます。保持する値の中身を自由に改変することだってできますし、関数で覆い隠すこともできます。実際、C言語の変数やポインタといった、かなりごちゃごちゃした性質も IORef でモデリングすることもできます。
変数がコードのブロック内に存在するのに、インタラクションと他を完全に分けることは、極めて奇妙、または率直に言ってありえなく見えてしまいます。状態を渡したい時や、データ構造の中に入れたい時もあるかもしれません。そういったときには、”箱”を用意するというアプローチ以外に道はないかもしれません。 Write Yourself a Scheme in 48 hours の”変数と代入”のチャプターが例を示しています。リンク先では、何故 State または ST ではなく、 IORef を用いて Scheme の環境をモデリングすることが最適化がうまく示されています。
簡単に言うと、( Scheme での)環境は任意のネストを構成し、ユーザーインタラクションによるインスタンスを保持したり( (define x 1) と Scheme REPL に入力されたら、 x と入力した際に1が返ってくることを期待しますよね)、 Scheme の関数からの参照を受ける働きなどがあります(Schemeでは関数は環境を捕捉します)。
まとめると、したいことが向いているならば State を用いると綺麗に仕上がる傾向があります。もし複数の状態が必要ならば、 ST を用いるとよいでしょう。しかしもし、状態を計算として扱うのが不便に感じるのであれば、可変のものとして扱うといいでしょう。そのとき IORef は最適解となります。"
実はこのコメントの最後に STM とか TVar を勧めていたんですけれど、一体どうなんでしょう…(^_^;)