[Haskell] IORef sharing

Timothy Goddard tim at goddard.net.nz
Mon Oct 27 19:43:14 EDT 2008


On Tue, 28 Oct 2008 12:02:54 Rodney D Price wrote:
> My old, deeply flawed mental picture had "iio" taking
> the role of a pointer to a value.  My bright, shiny
> new mental picture has "iio" acting just like a C
> #define macro: every time I call "iio", I'm really
> just writing "newIORef 0".  Is that what you're saying?
>
> -Rod

No, this isn't the behaviour of IORefs at all - you're getting mixed up with 
Haskell's syntax. <- in a do block means perform the contained action and let 
me use the result. = defines a term and is effectively just an alias - it 
doesn't run anything by itself.

> iio :: IO (IORef Int)
This means "iio is an IO operation which produces an IORef to an Int"
> iio = newIORef 0
This means "iio is creating a new counter starting at 0"
> ic1 = do { io <- iio ; count io 0 }
This is an IO operation which runs iio, creating a new IORef in the process, 
and then starts a counter at 0 and returns it.
> ic2 = do { io <- iio ; count io 0 }
This runs iio again, creating another IORef, and then starts a counter on the 
new IORef.

Haskell doesn't have mutable global variables - it goes against the grain of a 
pure language. You have to create the IORef within an IO procedure and pass 
it in. You really should write:

counter = do
  io <- newIORef 0
  c1 <- count io 0
  c2 <- count io 0
  c1 'a' >>= print
  c2 'b' >>= print
  c2 'a' >>= print
  c1 'a' >>= print

This should behave as you expected - it creates the IORef then creates two 
counters sharing it.

Remember that when you return IO a, you're returning an IO operation that 
produces an a. That operation is not run until it is bound to the main IO 
monad. Haskell's IO looks like any other language if you're only writing and 
calling procedures normally but as soon as you start passing around 
references to IO procedures you need to understand a little more about how 
monads work.

In the real world using IO counters is probably something to avoid. Only the 
part of your program that is actually interacting with the outside world 
should use IO at all, and keeping an internal count doesn't need this. 
Minimise IO and Haskell will reward you. Let IO spread all through your 
program and it will be no safer than the C the developer was really thinking 
in.

Cheers,

Tim


More information about the Haskell mailing list