Rodney D Price wrote:
I'm trying to understand how an IORef (MVar, TVar) might be
shared between separate instances of function closures.
I've defined a function `count` that returns a function with
an IORef "inside",

count :: IORef Int -> Int -> IO (Char -> IO Int)
count io i = do
  writeIORef io i
  return (\c -> if c == 'a'
                then modifyIORef io (+1) >> readIORef io
                else readIORef io)

Now I define an IORef and a couple of counters that share
the IORef,

iio :: IO (IORef Int)
iio = newIORef 0
ic1 = do { io <- iio ; count io 0 }
ic2 = do { io <- iio ; count io 0 }

I expected to see the counters sharing the IORef, so that
executing `counter1` below would print "1,1,2,3".  Instead,
it prints "1,0,1,2".

counter1 = do
  c1 <- ic1
  c2 <- ic2
  c1 'a' >>= print
  c2 'b' >>= print
  c2 'a' >>= print
  c1 'a' >>= print

However, if I create the two counters inside the same do
block, I get the result I expected, "1,1,2,3".

counter2 = do
  io <- iio
  c1 <- count io 0
  c2 <- count io 0
  c1 'a' >>= print
  c2 'b' >>= print
  c2 'a' >>= print
  c1 'a' >>= print

So apparently my mental picture of an IORef as a pointer
to a value is wrong.  I need a new mental picture.  What's
going on here?

Naming the creation of a new IORef "iio" is not gonna make it return the same IORef every time you call iio. Imagine iio being expanded to its definition in your counter1 example (which is exactly what happens); would you still expect the result to be 1,1,2,3? If you want the IORef to be shared by different pieces of code, pass it around as an argument.

Kind regards,

Martijn.
_______________________________________________
Haskell mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell

Reply via email to