Module Initialisation? (was Re: [Haskell] (no subject))

Ben Rudiak-Gould br276 at cl.cam.ac.uk
Sun Oct 17 08:53:22 EDT 2004


Wolfgang Thaller wrote:

>  Adrian Hey wrote:
>
> > I'm puzzled about this idea of "module init action" in a
> > declarative language. Perhaps, if it's desirable to have some
> > module initialisation applied to a module if anything from it is
> > used, the way to do this would be to have a reserved identifier
> > specially for the purpose, like "main", but at the module level.
> > (Though this idea still seems a bit strange to me).
>
>  I don't see what's so strange about that.

I think his point is that some module init actions are run while others 
aren't, and it's not entirely clear how the distinction should be made. 
Currently it's possible to think of import declarations as simply 
bringing names into scope, but in the presence of module init actions 
import declarations have side effects.

In many languages you can refer to a function in another module by its 
fully qualified name even if that module hasn't been explicitly 
imported. This is a nice feature and I'd like to see it added to 
Haskell, but there's a tension between it and the module-init-action 
feature as currently specified: we would have to look through the whole 
program source for fully-qualified names in order to figure out which 
module actions will be run.

There would be no semantic problem if all module actions were always 
run, but this is impossible because it would have to include modules not 
installed on the user's machine, as well as modules that haven't even 
been written yet.

There is also no semantic problem if only "safe" actions like newIORef 
are used, but the current proposal provides no static guarantee of this.

In any case, I have an idea of how to solve this problem -- see below.

> > Since a lot of the concerns expressed about this seem to centre
> > around possible abuse of arbitrary IO operations in these top level
> > constructions, maybe the problem could be addressed by insisting
> > that a restricted monad was used, call it SafeIO say.

How about (forall s. ST s)?

We can require module init actions to have a type (forall s. ST s a) 
instead of IO a. The compiler or RTS wraps the actions with stToIO 
(which is a safe function) before executing them.

Benefits:

    * It's just as easy as before to allocate global refs (and global 
mutable arrays).
    * It's still possible to perform arbitrary IO actions (e.g. FFI 
calls), but you have to wrap them in unsafeIOToST -- a good thing since 
they really are unsafe. unsafeIOToST is much safer than unsafePerformIO 
when used in this way.

Problems:

    * stToIO (newSTRef 'x') doesn't have type IO (IORef Char).

This problem can be solved by adopting a reform that I've wanted for a 
long time anyway: make IO, IORef, etc. aliases for (ST RealWorld), 
(STRef RealWorld), etc. instead of completely different types. Then 
stToIO is the identity function and we only need a single set of 
state-thread functions instead of the parallel IO and ST equivalents 
that we have currently.

-- Ben



More information about the Haskell mailing list