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