我正在Haskell编写一个目前有类似数据类型的游戏程序
data World = World {
worldPlayer :: !(IORef GameObject),
worldEntities :: ![IORef GameObject],
...
}
每次更新时,以下更新都会写入播放器IORef
:
updatePlayer :: GameObject -> [IORef GameObject] -> IO GameObject
在此功能中,它会检查每个对象的碰撞,然后移动播放器。 但我希望updatePlayer函数是纯粹的,所以我需要使用不同的数据结构。
最明显的想法是从世界中获取[IORef GameObject]
并通过在每个索引上调用IO [GameObject]
将其转换为readIORef
。但这效率很低。
我发现这样做的另一种可能方法是使用Data.Vector.MVector
和Data.Vector.Generic.unsafeUnfreeze
以及unsafeFreeze
,其O(1)
性能可以worldEntities :: !(MVector (PrimState IO) GameObject)
。问题是unsafeUnfreeze
和unsafeFreeze
仅适用于某些数据类型。
我还找到了IOArray
,因此我可以使用IOArray Int GameObject
,但我找不到将IOArray
转换为不可变结构的方法。
最后,我可以IORef [GameObject]
或IORef (Vector GameObject)
,但我不确定这会有多高效。
最有效的方法是什么?
答案 0 :(得分:5)
您可以使用lenses而不是可变对象来获得“类似setter”的行为。在搞乱可变状态之前尝试一下,这在Haskell中非常难看(故意丑陋,不鼓励你这样做)。
(编辑添加:“类似setter”语法。镜头“setters”仍然创建对“set”ted结果的新引用,因此您仍需要对主循环进行排序以从setter返回的值中读取,当然,你不能重新读取旧的(不可变的)引用来获取更新的值。)