So I'm writing a game in Haskell, and I'm expressing a player's turn as a series of state-altering functions that correlate to various turn phases. Originally, this looks something like:
let game' = phase1 game
game'' = phase2 game'
-- etc.
Prime candidate for State monadosity, right? This leads to the more elegant:
do
phase1
phase2
-- etc.
However, then it seems like I have to change phase1
, phase2
, et al to begin with a boilerplate "State getting" step:
phase1 = get >>= \game -> -- ...
I'm hoping there's a way to abstract this out, so I can avoid boilerplate on both the caller and the callee. I'm just too new to know what this way is (this is my first real Haskell project). Any advice?
Well, it's not quite monadosic yet. This is a prime candidate for an Endo monoid. This leads to the more elegant
game = mconcat [ phase1, phase2, ... ]
And each phase is written:
phase1 = Endo $ \game -> ...
You would move to a monad if you needed to return a some additional data along with the new state in each phase. In that case a simple function will make your boilerplate more tolerable:
phase :: (GameState -> GameMonad a) -> GameMonad a
phase f = f =<< get
And then a phase is written:
phase1 = phase $ \game -> do ...
But if you want to use the state, you are probably going to have to give it a name (unless you can finagle pointfreeness by, say, using gets or data-accessor), and in that case you can't get much terser than a function and a lambda.
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