views:

154

answers:

1

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?

+6  A: 

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.

luqui
Or `game = mconcat $ map Endo [phase1, phase2, ...]` and `phase1 game = ...`
trinithis
`appEndo . mconcat . map Endo = foldr (.) id` I am proposing the use of `Endo` more as an abstraction, rather than just a technique to compose a list of functions. I don't know what I mean by that though :-P
luqui