Haskell最有效的可变数据结构

时间:2014-01-29 23:09:47

标签: arrays performance haskell data-structures functional-programming

我正在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.MVectorData.Vector.Generic.unsafeUnfreeze以及unsafeFreeze,其O(1)性能可以worldEntities :: !(MVector (PrimState IO) GameObject)。问题是unsafeUnfreezeunsafeFreeze仅适用于某些数据类型。

我还找到了IOArray,因此我可以使用IOArray Int GameObject,但我找不到将IOArray转换为不可变结构的方法。

最后,我可以IORef [GameObject]IORef (Vector GameObject),但我不确定这会有多高效。

最有效的方法是什么?

1 个答案:

答案 0 :(得分:5)

您可以使用lenses而不是可变对象来获得“类似setter”的行为。在搞乱可变状态之前尝试一下,这在Haskell中非常难看(故意丑陋,不鼓励你这样做)。

(编辑添加:“类似setter”语法。镜头“setters”仍然创建对“set”ted结果的新引用,因此您仍需要对主循环进行排序以从setter返回的值中读取,当然,你不能重新读取旧的(不可变的)引用来获取更新的值。)