
On Tue, Jan 08, 2008 at 09:10:59PM +0100, Achim Schneider wrote:
Don Stewart
wrote: jules:
Achim Schneider wrote:
things like
data State = State { winSize :: IORef Size , t :: IORef Int , fps :: IORef Float , showFPS :: IORef Bool , showHelp :: IORef Bool , grabMouse :: IORef Bool , mousePos :: IORef (Maybe Position) , mouseDelta :: IORef Position , viewRot :: IORef Vec3 , angle' :: IORef GLfloat , ballPos :: IORef Vec2 , ballVel :: IORef Vec2 }
Yuck!
I'm not sure whether this is a real example or not, but if it's real, get rid of all those IORefs. Make State a simple type, and use (IORef State) as needed for callbacks, and hide that fact in other code.
I agree, this is very-unHaskelly :)
The State type should be a simple purely functional structured, threaded through your code via a StateT or some such. Not a bunch of pointers in IO.
See xmonad for examples of this in highly effectful programs,
http://code.haskell.org/xmonad/XMonad/Core.hs
newtype X a = X (ReaderT XConf (StateT XState IO) a)
(Carries read-only and updatable state components)
Yes, you see, that was my first Haskell program bigger than 20 lines, there's no possibility to get the state out of the IO Monad, at least without writing a high-level interface to glut and gl, and then there's this thing that _every_ game works with input callbacks, one, global, state update function (where it doesn't _really_ matter whether you're passing and returning a state or updating a state) and one function that translates the state into some graphics representation.
That said, I think it's not very Haskell-like to do something elegantly in 1000 lines when you can do it in 100 lines and still have it look nicer than C.
I would use IORef State. Making illegal states unrepresentable greatly helps with code prettiness; the original State allowed internal aliasing, which is quite definitely silly. I think this should be written somewhere as a general rule - when you have a mutable structure, use a reference to a record, not a record of references. Stefan