对于 Haskell 中的矢量图形库,我必须携带一个相当大的状态:线条描边参数、颜色、剪辑路径等。我知道有两种方法可以做到这一点。引用来自的评论哈斯克尔咖啡馆 http://www.mail-archive.com/haskell-cafe@haskell.org/msg71839.html:“我建议您要么使用具有可变状态的读取器 monad,要么使用具有不可变状态的状态 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 来读取和更新大状态,但由于我经常遇到这种模式,我希望有更好的方法。