[Haskell-cafe] Current situation regarding global IORefs

Cale Gibbard cgibbard at gmail.com
Fri Apr 21 14:24:27 EDT 2006


On 21/04/06, Brian Hulley <brianh at metamilk.com> wrote:
> Robert Dockins wrote:
> > On Apr 21, 2006, at 10:34 AM, Brian Hulley wrote:
> >> Robert Dockins wrote:
> >>> On Apr 21, 2006, at 9:56 AM, Brian Hulley wrote:
> >>>
> >>>> Hi -
> >>>> I've run into the global mutable state problem described in http://
> >>[snip]
> >>
> >> There is only one GUI for the application and only one control in
> >> it can have the keyboard focus so it seems natural to use global
> >> state here
> >
> > I'd suggest you consider not making those assumptions... they are the
> > kinds of assumptions that can make later code reuse and maintenance
> > more difficult than it should be.  (Obviously, if code reuse/
> > maintenance is a low priority then it doesn't matter).
> >
> >> , but I suppose I could also look into using a state monad. The
> >> advantage (perhaps also disadvantage ;-) ) of global state is that
> >> it allows me to easily convert all my old C++ singleton classes to
> >> Haskell modules...
> >
> > <ramble type="somewhat coherent">
> > Ahhh... the singleton pattern.  There is a debate among OO theorists
> > about whether the singleton pattern is actually a good idea.  I tend
> > to side with those who say that it is Just Wrong. [snip]
>
> Thanks for the comments. I've now changed everything so that controls use a
> ManagerM monad which wraps up the state instead of using the IO monad so
> there are no longer any global variables. It wasn't as difficult as I had
> thought and as you say it makes everything much more scalable, although at
> the expense of having to use liftIO in various places.
>
> I've defined my state monad by:
>
> data MState = MState {keyboard:: !Maybe Control} -- etc - other state here
> also
> type ManagerM a = StateT MState IO a
>
> and everything works ok. However if I try to use a newtype instead of a type
> (to completely hide the representation) eg
>
> newtype ManagerM a = ManagerM (StateT MState IO a) deriving (Monad, MonadIO,
> MonadState)
>
> it won't compile. Does this mean it is not possible to wrap combined monads
> in a newtype? I notice that the examples in tutorials I've looked at tend to
> always just use type instead of newtype.
try deriving (Monad, MonadIO, MonadState MState) -- I find that
newtype deriving doesn't like guessing at other class parameters, even
with the fundeps there.

> Another point is that I'm not sure what is the "proper" way to represent the
> state itself ie should each component of the state be a separate IORef to
> avoid having to copy the whole state each time or is it better practice to
> just use an immutable record as I've done above?

If you were to use IORefs/MVars, it would likely be enough to use
ReaderT instead of StateT, since you likely wouldn't be replacing your
mutable cells, just their contents. Both routes are okay -- note that
Haskell data structure nodes are usually just bunches of pointers to
values (or more properly, code which returns values) anyway, so you
should only be copying a few pointers when updates are made. (In a
similar way to how replacing the head of a list is constant time and
space, and not linear.)

 - Cale


More information about the Haskell-Cafe mailing list