首页 > 解决方案 > 如何正确更新 Data.IORef 中保存的 Haskell 记录?

问题描述

我有一个简单的项目,我尝试在其中尝试使用 Haskell 和 Cairo 库。

我在重绘应用程序状态时遇到了问题。目前我有保存全局状态的记录。我必须将它存储在Data.IORefmonad 中,以便能够将数据从一个 GUI 事件传递到另一个。

我受到 Elm 的启发尝试那样做,但我想知道是否有更好的方法来做到这一点?

我特别关心 main 函数中的这个片段。

-- update globalModel in place
readIORef globalModel >>= (\m -> writeIORef globalModel (Model
                                                         (fromIntegral kv)
                                                         (if ((keyToHeading (fromIntegral kv)) == None)
                                                           then (heading m)
                                                           else (keyToHeading (fromIntegral kv)))))

请建议更好的方法。

标签: haskell

解决方案


这可能是一个更简单的重构。请注意,modifyIORef'readIORefand组合writeIORef成一个严格的操作:

ifNoneThen :: Heading -> Heading -> Heading
None `ifNoneThen` x = x
h    `ifNoneThen` _ = h

updateModel :: Int -> Model -> Model
updateModel kv oldModel = Model newKv newHeading
    where newKv      = fromIntegral kv
          newHeading = keyToHeading newKv `ifNoneThen` heading oldModel

foo :: Int -> Model -> IO ()
foo kv globalModel = modifyIORef' globalModel (updateModel kv)
  • Headers 的一个小实用函数ifNoneThen(您也可以在其他地方使用)清理if代码主体中的语句。
  • 一些小的重构以删除重复的调用(fromIntegral kv 如果你可以调用一次并给结果一个有意义的名称,为什么要调用 3 次?)。
  • 从不纯代码中分解出纯代码(从旧模型构建新模型)(更新IORef.

推荐阅读