[Haskell] IORef sharing

Martijn van Steenbergen martijn at van.steenbergen.nl
Mon Oct 27 18:36:37 EDT 2008


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.


More information about the Haskell mailing list