My program has a client and a server component that need to communicate. They each have a state that they mutate. The mutation is done explicitly in the following way:
There a relation
class Diff a b where
commit :: a -> b -> a
That says that type b
can be considered a 'chunk' of type a
and that you can modify objects of type a
by 'committing' object of type b
to them.
So you modify the state, those chunks get logged and transmitted to the client which also has an instance of the above relation, just for a different type a
.
Now, here's the deal. My server's state is a record with many field. All of them can change since, you know, it's a state. That's what it does. This leaves me having to write a separate case in my 'chunk' type for each possible field so I can transmit them over the network. It would be lovely if I could somehow transmit any state -> state
function, but I don't see that happening. The client shares the servers code, so it does know about the structure of my 'chunks', and the part where it has to interpret them to update it's own, local, state is something that I can manage.
What I was wondering is if I could maybe use lens here to automate the generation of update chunks. All my 'chunk' type is, after all, is a clumsy setter with a generic structure I can serialize.
What would be the best way to avoid repeating code here?
To give you a better idea of how my code currently looks, here's an example of how the server's state looks for a game of pong.
data State = State
{ playerPaddle :: Double
, aiPaddle :: Double
, ball :: Vec2 Double
, ballV :: Vec2 Double } deriving Show
data Update = BallPos (Vec2 Double)
| BallVel (Vec2 Double)
| PlayerPos Double
| AIPos Double
instance Diff State Update where
commit s (BallPos p) = s { ball = p }
commit s (BallVel p) = s { ballV = p }
commit s (PlayerPos p) = s { playerPaddle = p }
commit s (AIPos p) = s { aiPaddle = p }