I am writing a game program in Haskell that currently has a data type like this
data World = World {
worldPlayer :: !(IORef GameObject),
worldEntities :: ![IORef GameObject],
...
}
Each update, the following update is written to the player IORef:
updatePlayer :: GameObject -> [IORef GameObject] -> IO GameObject
In this function, it checks for collision on each object, then moves the player. But I would like the updatePlayer function to be pure, so I need to use a different data structure.
The most obvious idea is to take the [IORef GameObject] from the world and transform it into an IO [GameObject] by calling readIORef on each index. But this would be very inefficient.
Another possible way I found to do this is using Data.Vector.MVector and Data.Vector.Generic.unsafeUnfreeze and unsafeFreeze, which have O(1) performance to do worldEntities :: !(MVector (PrimState IO) GameObject). The problem is that unsafeUnfreeze and unsafeFreeze only work on certain data types.
I also found IOArray, so I could use IOArray Int GameObject, but I cannot find a way to convert IOArrays into an immutable structure.
Last, I could just do IORef [GameObject] or IORef (Vector GameObject), but I am unsure how efficient this would be.
What is the most efficient way to do this?
Worldevery update.GameObjectis precisely. Returning a new object will certainly be less efficient than mutating, but probably not as much as you think, and it's certainly a lot easier! It can actually be very fast if little changes between updates and you can share a lot of the old structure.IORef. Maybe you could give a bit more of your game code?