Reputation: 17051
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?
Upvotes: 4
Views: 450
Reputation: 60463
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.
Upvotes: 8