[Haskell-cafe] Stupid newbie question of the day: why is newMVar in the IO monad?

Brian Hurt bhurt at spnz.org
Thu Apr 17 14:14:14 UTC 2014


So, I've hit a problem, and I'm wondering why this is.  I want to write a
function which returns a global monotonically incrementing int.  This
*should* be easy- just put a MVar in a global name, then update it as
necessary:

globalCounter :: MVar Integer
globalCounter = undefined

genId :: IO Integer
genId = modifyMVar (\i -> (i+1, i)) globalCounter

The problem with this is defining globalCounter- and that is because
newMVar returns IO (MVar a), and not just MVar a.  Now, I can go:

globalCounter = unsafePerformIO $ newMVar 0

but I hate using unsafePerformIO.  And I don't want to pass around the
reference itself- I need to be in the IO monad with a StateT transform on
top for other reasons, I don't want to complicate things.  And even if I
were, I would just pass the counter around instead of the reference.  But
it just feels like Haskell is being gratuitously difficult here.

It's not just the name, it's the fact that creating the MVar is
*explicitly* modifying the state of the world, which implies there is
something more going on here than just allocating some memory.  As an
example of what I mean, newSTRef returns ST s (STRef s a).  This is
explicitly saying that the created STRef is only visible in the given
thread.  This is necessary for the implementation of the STRef, which is a
mutable variable with no transactional guarantees.  If it were visible from
another thread, then it could be accessed from the other thread, creating a
potential race condition.  That I understand.  But that isn't the case
here- MVar's are explicitly designed to be accessed from multiple threads.

So then I thought that it was something specific with MVars- maybe they
need to do an OS call to set them up or something.  OK, so let's try some
alternatives.  Like STM.

Nope.  newTVar has return type STM (TVar a) and newTMVar returns STM (TMVar
a).  Throw these into atomically, and I'm right back to where I started.
 newIORef returns IO (IORef a).  And that's just a pointer store (I
thought).

It's easier for me to believe that I'm missing something here, rather than
that Haskell is just being gratuitously difficult.  But I honestly don't
see what it is I'm missing.  Help?

Brian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20140417/350947c0/attachment.html>


More information about the Haskell-Cafe mailing list