私の Haskell のベクター グラフィックス ライブラリでは、かなり大きな状態 (ライン ストロークのパラメーター、色、クリップ パスなど) を持ち歩かなければなりません。これを行う方法は 2 つあります。Haskell-cafeからのコメントを引用すると、「可変状態のリーダー モナドか、不変状態の状態モナドを使用することをお勧めします」。
これが私の問題です。大きな不変状態を更新すると、パフォーマンスが低下します。多くの STRef を使用することは、Haskell で C を書くようなものです。冗長で醜いです。
不変の状態は次のとおりです。
data GfxState = GfxState {
lineWidth :: Double,
lineCap :: Int,
color :: Color,
clip :: Path,
...
}
setLineWidth :: Double -> State GfxState ()
setLineWidth x = modify (\state -> state { lineWidth = x })
私が知る限り、「state { lineWidth = x }」は新しい GfxState を作成し、古いものをガベージ コレクションできるようにします。状態が大きく、頻繁に更新される場合、これはパフォーマンスを低下させます。
変更可能な状態は次のとおりです。
data GfxState s = GfxState {
lineWidth :: STRef s Double,
lineCap :: STRef s Int,
color :: STRef s Color,
clip :: STRef s Path,
...
many more STRefs
}
setLineWidth :: GfxState s -> Double -> ST s ()
setLineWidth state x = writeSTRef (lineWidth state) x
(GfxState s) と (ST s) と (STRef s) がいたるところに表示されるようになりました。これは、冗長で紛らわしく、短くて表現力豊かなコードを書く精神に勝っています。C + FFI を使用して大きな状態を読み取って更新することもできますが、このパターンに頻繁に遭遇するので、もっと良い方法があることを願っています。