Module Initialisation? (was Re: [Haskell] (no subject))
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.
* It's just as easy as before to allocate global refs (and global
* 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.
* 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.
More information about the Haskell