[Haskell-cafe] Re: Yet another IO initializer: Effectful declarations and an ACIO monad

Ian.Stark at ed.ac.uk Ian.Stark at ed.ac.uk
Fri Nov 26 06:28:54 EST 2004

On Fri, 26 Nov 2004, George Russell wrote:

> Ian Stark wrote (snipped):
>  > Way back in this thread, Koen Claessen mentioned the idea of a commutative
>  > version of the IO monad for handling things with identity.  That doesn't quite
>  > do it, but I have a refinement that might.  The thing is to focus on IO
>  > computations that are:
>  >
>  >  a) central -- their effect commutes with every other IO action
>  >  b) affine  -- their effect is not directly observable, and can be discarded.
> Unfortunately I have a number of examples where I use global variables with
> initialisation actions which cannot conceivably be proven to be central & affine
> by the compiler.  For example, where I want to call up an external program (such
> as wish) which I will later use for doing graphics.

This indeed can't be proved central+affine, because it isn't.  So instead,
choose one of the following:

1 (Good) Indirection:

  declare gc <- newIORef None; so that gc is a global variable holding a
  (Maybe GraphicsContext).  Initialise the contents in your main IO
  action; and then pull out the value any time you need to look at it.

  Yes, you need to explicitly initialise it; but you don't need then to
  pass the initialized handle all around your code.  The painful plumbing
  goes away.

2 (Neutral) As above, but write getGC :: IO GraphicsContext that looks in
  gc, and if there is None then calls out to wish, or whatever, to
  initialise it first.

  Sound, but getGC then hides some wildly varying behaviour.

3 (Evil) Give in to the dark side.  Have unsafeIOtoACIO, write a
  declaration using it, and hope that your compiler does the easy thing
  and executes all declarations at the start of the program.

  In fact not much worse than (2); only now the possible effect points
  have leapt from all uses of gc to all uses of IO.

> The Haskell libraries would run into a similar problem when they tried to
> open stdin/stdout/stderr.

But they don't open them, right?  The whole point of stdin/stdout/stderr
being fixed integers is that these handles are already opened when the
program starts.

> Or indeed when they tried to implement RandomGen, which I presume is
> going to want to get at the system clock to seed the random number
> generator.

Yes, the system StdGen really does have to get initialised.  But the
presumed readRandomNumberFromSystem() is ACIO if it's random (OK, so if
it's implemented by opening /dev/random, then this would have to be
wrapped in assertIOisACIO).

Ian Stark                               http://www.ed.ac.uk/~stark
LFCS, School of Informatics, The University of Edinburgh, Scotland

More information about the Haskell-Cafe mailing list