[Haskell] Re: Global Variables and IO initializers

Koen Claessen koen at cs.chalmers.se
Thu Nov 4 12:28:56 EST 2004


Ben Rudiak-Gould wrote:

 | I'm not convinced this is a problem either. All you have
 | to do is use a single parameter (?MyModule.globals ::
 | MyModule.Globals), where MyModule.Globals is an abstract
 | type, and you've hidden your implementation as completely
 | as if you had used unexported global variables.

Are you suggesting to always add the context
(?MyModule.globals :: MyModule.Globals) to every function in
every module you implement? (My example concerned a module
that was previously implemented without global variables,
and now was going to be implemented with global variables.)

 | [...] The original implicit-parameter paper suggested an
 | extension of Haskell to support partial constraints in
 | type signatures, e.g.
 |
 |     pretty :: ... => Doc -> String
 |
 | with the unspecified constraint being filled in by the
 | type inferencer (section 5.4).

(Ah! I had forgotten about that. See also:

  http://www.mail-archive.com/haskell@haskell.org/msg05186.html

:-)

 | I think the OP is proposing the same thing, except
 | without the ellipsis: i.e. we just write
 |
 |     pretty :: Doc -> String
 |
 | and the compiler infers pretty :: (?width :: Int) => Doc
 | -> String, or whatever. This actually sounds like a very
 | good idea to me.

I think hiding the fact that certain objects are not
constants but functions is a bad idea, because it will break
sharing in a lazy implementation.

 | Adrian Hey proposed a "SafeIO" monad with similar
 | properties to yours. I have the same objection to both of
 | them: a whole new monad and a bunch of interconversion
 | functions seems like overkill for such a minor new
 | language feature.

I was not aware of his proposal. I don't think it is that
bad:

  * 1 new monad

  * for each current safe IO operation, 1 new operation
    (read: newIORef. What else?)

  * possibly, a function convertCIOtoIO :: CIO a -> IO a

 (* part of compilers: a function unsafeIOtoCIO :: IO a -> CIO a)

That's it!

 | And I have the same counter-proposal: why not use (forall
 | s. ST s)? It's not commutative, but I think it has all of
 | the properties we need.

Interesting idea. However, when I then provide a function
for creating an IORef (which is what this extension would be
used for mostly), I get this:

  newIORefST :: a -> ST s (IORef a)

Which is probably not what you want.

 | So importing a module doesn't have side effects, and init
 | actions can be implemented easily using unsafePerformIO
 | without affecting the semantics.

I don't understand this remark.

 | Note that the ST monad does not require higher-order
 | polymorphism -- only the runST function requires that. ST
 | is still useful without runST, as this example
 | demonstrates.

So, if I get it right, you want to use (forall s . ST s)
because it avoids adding yet another monad to Haskell?

Regards,
/Koen


More information about the Haskell mailing list