functorial
functorial

Reputation: 687

Haskell Most Efficient Mutable Data Structure

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?

Upvotes: 1

Views: 1659

Answers (1)

misterbee
misterbee

Reputation: 5172

You can use lenses instead of mutable objects, to get "setter-like" behavior. Try that before messing around with mutable state, which is very ugly in Haskell (intentionally ugly, to discourage you from doing it).

(Edit to add: "setter-like" syntax. Lens "setters" still create new references to the "set"ted result, so you still need to sequence your main loop to read from the returned value from the setter, you can't re-read an old (immutable) reference to get an updated value, of course.)

Upvotes: 5

Related Questions