3 ms·
In the most naive way of doing such things, there is indeed such a tradeoff. So let's say that my Player is now allowed to collect Rice, which he will use in ce
by drostie 13y ago
In the most naive way of doing such things, there is indeed such a tradeoff. So let's say that my Player is now allowed to collect Rice, which he will use in certain eat() functions.
If Player is a data structure, I could add the rice counter to the Player and then modify all of my functions to "pass through" the rice. If the game is small enough, this makes the most sense. This is not as bad as it sounds because the typechecker will get angry about any Player functions in the code which do not have rice. So I've got the language on my side when I want to "make sure I've got all of them," it's not just a haphazard grep for the token "Player".
I could also write everything dogmatically with a pattern matching syntax which passes through all of the rest of the data. This is embodied in the examples below so I won't re-write it.
On the other hand, I can treat the game as a module, create a new data structure `PlayerWithRice {player :: Player, rice :: Int}`. Then I can define `addRice :: (Player -> Player) -> PlayerWithRice -> PlayerWithRice` which takes a function for modifying players without rice, and turns it into a function for modifying players with. Then there's just a list of new declarations in a new module which add rice to existing code.
This all sounds complicated! Surely there's something simpler? There are a few simpler ideas: one is called a Monad Transformer. The Player can be stored in a slightly more complicated way at first, so that it "wraps" another object which holds "all future data-to-be-added". All of your existing code written in this context will just automatically pass this 'future' data through. For PlayerWithRice you simply fill in the 'future' data as a data structure which holds rice and also more future data.
Second, there are lenses, which the above article discusses. If you write every set/get with lenses, then updating the data structure only requires updating those lenses, and all the rest of the code will follow. Again, you'll have a type-checker on your side to guarantee that you didn't miss anything crazy when you update those lenses.