I've got these data types:
data PointPlus = PointPlus
{ coords :: Point
, velocity :: Vector
} deriving (Eq)
data BodyGeo = BodyGeo
{ pointPlus :: PointPlus
, size :: Point
} deriving (Eq)
data Body = Body
{ geo :: BodyGeo
, pict :: Color
} deriving (Eq)
It's the base datatype for characters, enemies, objects, etc. in my game (well, I just have two rectangles as the player and the ground right now :p).
When a key, the characters moves right, left or jumps by changing its velocity
. Moving is done by adding the velocity
to the coords
. Currently, it's written as follows:
move (PointPlus (x, y) (xi, yi)) = PointPlus (x + xi, y + yi) (xi, yi)
I'm just taking the PointPlus
part of my Body
and not the entire Body
, otherwise it would be:
move (Body (BodyGeo (PointPlus (x, y) (xi, yi)) wh) col) = (Body (BodyGeo (PointPlus (x + xi, y + yi) (xi, yi)) wh) col)
Is the first version of move
better? Anyway, if move
only changes PointPlus
, there must be another function that calls it inside a new Body
. I explain: there's a function update
which is called to update the game state; it is passed the current game state, a single Body
for now, and returns the updated Body
.
update (Body (BodyGeo (PointPlus xy (xi, yi)) wh) pict) = (Body (BodyGeo (move (PointPlus xy (xi, yi))) wh) pict)
That tickles me. Everything is kept the same within Body
except the PointPlus
. Is there a way to avoid this complete "reconstruction" by hand? Like in:
update body = backInBody $ move $ pointPlus body
Without having to define backInBody
, of course.
You're looking for "lenses". There are several different packages for lenses; here is a good summary of them.
My understanding is that a lens on a data type a
for some field b
provides two operations: a way to get the value of b
and a way to get a new a
with a different value of b
. So you would just use a lens to work with the deeply nested PointPlus
.
The lens packages provide useful functions for working with lenses as well as ways of generating lenses automatically (with template Haskell) which could be very convenient.
I think they are worth looking into for your project, especially because you are likely to encounter similar problems with nesting in other places thanks to the structure of your data types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With