Monad facade for a MonadState in Haskell

Background: I'm creating a game with a stateful monad for reading and writing changes to the global state of the game.

I would like to divide my game into components, such as "Characters", providing a domain specific way for these components to interact with the global state. Ideally this might be define specific actions of the form MonadState Character m => m a that I could use, but each such m a would enact changes on the parent (global state).

I've searched around for converting between state monads, or providing an interface from one state monad to another, but the specific language for this is beyond my scope of knowledge. I am also already using Lenses, and I'm wondering if I can do something with them.

EDIT:

I'd like to be able to do something like moveCharacter :: MonadState Character m => Int -> Int -> m ()

and have that perform move :: MonadState World m => Int -> Int -> m () inside. Basically, abstracting the world specifics away from the character.

Thanks!

Upvotes: 1

Views: 96

Answers (2)

Jeremy List
Jeremy List

Reputation: 1766

You actually need 2 conversion functions: one to extract the character from the world and another one to modify the world with the modified character. You can put them together like this:

extractCharacter :: World -> Character
extractCharacter = error "Tried to call placeholder function"

replaceCharacter :: World -> Character -> World
replaceCharacter = error "Tried to call placeholder function"

runCharacterSubroutine :: (Functor m) =>
  StateT Character m a -> StateT World m a
runCharacterSubroutine act = StateT $ \w ->
  fmap (\(a,c') -> (a,replaceCharacter w c')) $
  runStateT act (extractCharacter w)

In your game, you probably want something a little more complicated, but that's just a matter of adding an extra parameter to extractCharacter and replaceCharacter

Note that the function I gave only works if the StateT is at the top of the monad transformer stack. If it's not: you will have to use the mmorph package

Upvotes: 0

Daniel Wagner
Daniel Wagner

Reputation: 153182

Sounds like you're looking for Zoom, which lets you convert a stateful action on the view of a lens into a stateful action on the source of the lens.

Upvotes: 3

Related Questions