[Haskell-cafe] Re: [Haskell] Making 'Super Nario Bros' in Haskell

Achim Schneider barsoap at web.de
Thu Oct 30 02:12:05 EDT 2008


"Eli Ford" <eford at griptonite.com> wrote:

> > > Is there a better way than IORefs
> > >
> > The state Monad.
> 
> Do you mean one state shared among all actors, like this?
> 
> 	type MGame = State GameState
> 	newtype GameState = GameState { <shared state> }
> 
> That gets part of the way, but I'm thinking of a situation where each
> instance of a particular type of actor can have its own reference to
> some other actor:
> 
> 	newtype Watcher = Watcher {
> 			otherActor :: IORef ActorWrapper
> 		}
> 
> (Here, ActorWrapper is an existential type that hides a specific actor
> type.)
> 
> I started writing a game using IORefs that way, allowing actors to see
> and cause changes in each other, but in the back of my mind I wonder
> if this is a symptom of a C++ background.
>
As a general rule, if you're thinking IORef's you aren't thinking
Haskell.

You shouldn't think of a global state Monad as state being shared
between all actors, but capturing the state of many actors at a
particular instance of time: The state Monad, by itself, encapsulates
time, not data. The data encapsulation is done by the type
of the state, something like

MyState = MyState { actors::(Map UKey Actor), ... }

where UKey is unique for the whole run-time of the game, that is, if
you store e.g. a reference to a door in the state of a switch, you can
make the switch explode (either in the frame-global update or when
triggered) if Mario happened to jump on the door and thus destroyed it.
(Please don't take this as an example of good game design)

If you look at the source of MonadState, you'll notice that it doesn't
care about what you put into it, at all. It's merely pure imperative
sugar that allows you to pretend not to be programming in a functional
language.

My model, of course, doesn't really differ from yours except that it
can't blow up that badly as eg. you can't ever modify your game state
from inside draw or mess with gl in update.

As a general rule, always try hard to restrict usage of the IO Monad
to the main function. It doesn't mean that you can't code imperatively
and side-effect full in the rest of your program, it just means that
you can't launch nuclear missiles and cause major side effects outside
of your program.

Nothing is stopping you from further restricting side-effects by using
the state Monad on two different types to eg. seperate the GUI state
from the game state, so that you can't ever select a menu item when
Mario collects a mushroom or similar insanities. Decide for yourself
how much granularity you want.


One of the strangest features of Haskell is that, despite and because of
being an uttermost functional language, it actually promotes imperative
programming in the guise of monadic programming.

-- 
(c) this sig last receiving data processing entity. Inspect headers
for copyright history. All rights reserved. Copying, hiring, renting,
performance and/or quoting of this signature prohibited.



More information about the Haskell-Cafe mailing list