Для моей векторной графической библиотеки в Haskell я должен нести вокруг довольно большого состояния: параметры штриховки линии, цвета, путь клипа и т.д. Я знаю два способа сделать это. Цитируя комментарий Haskell-cafe: "Я бы предложил вам использовать монаду-читатель с изменчивым состоянием или государственную монаду с неизменяемым состоянием".
Вот моя проблема: обновление большого неизменяемого состояния - это убийство производительности. Использование большого количества STRef похоже на запись C в Haskell: она многословная и уродливая.
Вот неизменное состояние:
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) по всему месту, что является многословным, запутанным и превосходит дух написания короткого и выразительного кода. Я мог бы использовать C + FFI для чтения и обновления большого состояния, но поскольку я часто встречаюсь с этим шаблоном, я надеюсь, что там будет лучший способ.