私が理解していることから、IORef
s への変更は非常に迅速であり、サンクポインターを更新するだけです。もちろん、読者 (つまり、自分の Web ページで値を確認したい人) は、時間をかけてこれらのサンクを評価する必要があります (ライターが結果を読み戻していない場合、サンクが蓄積される可能性があります)。
IORef
多くの状況では、いずれにせよ何らかの時点で評価する必要があるためです (明らかに、これは無限のデータ構造で壊れます) 。
そこで、 と同様のシグネチャを使用して、次の関数を作成しましたatomicModifyIORef
。
atomicModifyIORefPar :: (NFData a) => IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORefPar ioref f =
let
g olddata =
let (newdata, result) = f olddata in (newdata, (result, newdata))
in do
(result, newdata) <- atomicModifyIORef ioref g
force newdata `par` return result
これはうまくいくようです(テストコードはこちら)。ここで何か間違ったことはありますか?または、これを行うより良い方法はありますか?
編集:2回目の試み
以下のカールの回答に触発されました。実際に に格納force newdata
しますIORef
。これはとにかく同じnewdata
ですが、後で保持したいランタイムを示しているforce newdata
ため、スパークのガベージ コレクションは行われません。
atomicModifyIORefPar :: (NFData a) => IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORefPar ioref f =
let
g olddata =
let
(newdata, result) = f olddata
newdata_forced = force newdata
in
(newdata_forced, (result, newdata_forced))
in do
(result, newdata_forced) <- atomicModifyIORef ioref g
newdata_forced `par` return result