对于我在 Haskell 中的矢量图形库,我必须携带一个相当大的状态:线条描边参数、颜色、剪辑路径等。我知道这样做的两种方法。引用Haskell-cafe的评论:“我建议你要么使用具有可变状态的 reader monad,要么使用具有不可变状态的 state monad”。
这是我的问题:更新一个大的不可变状态会导致性能下降。使用大量 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 并让旧的 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 来读取和更新大状态,但是由于我经常遇到这种模式,我希望有更好的方法。