Adrian Hey wrote:
We've been talking about
this problem for years, but nothing is ever done about it (a solution to
this problem isn't even on the agenda for Haskell' AFIAK).

The problem needs talking about, it's important.

My objection was the implication that top-level mutable state was the right answer to the OP's question, which my strong hunch is it isn't. I don't deny the existence of a problem here.

No. Even if we stripped away all other code apart from the Haskell rts
itself (OS, device drivers etc) and performed your IO entirely in
Haskell (just using peek and poke on bare hardware), you'd still need
top level mutable state to implement common IO API's (e.g. The socket
API, does anybody really believe this is entirely stateless?).

I'm not sure that's quite to the point. Clearly we can set up state at the top of our main action:

main = do
  sockstate <- initSocks
  graphstate <- initGraphics
  ...
  disposeGraphics graphstate
  disposeSocks sockstate
  exit


Voila. Mutable state which persists for our entire program.

Arguably it's a pain passing around the state explicitly. Alternatively, you can argue that passing this stuff around explicitly makes code much easier to reason about. And we know a dozen tricks to hide this stuff (reader monads, state monads, withSocketsDo-style bracket constructs).

So I don't think this is really the issue, is it?

As I understood it, the issue was more about whether or not *library* modules should be allowed to some 'set up' initialisation code to run at the beginning of 'main' to start up their own global state. I was never convinced this was a nice idea (I don't like the thought than an 'import' alone can add hidden IO actions to main). Mind you, I'm not convinced it's wrong, either. I think it's a hard one.

I wouldn't dispute the assertion that at the level of complete programs
or processes, implementations that don't use "global variables" are
possible. But this does not hold at the level of individual IO library
API's. If we want to keep our software *modular* (I take we do), then
we need top level mutable state.

That's assuming you feel having an explicit 'init' command and a 'withLibXYZDo' construct breaks modularity. It doesn't feel like a terrible modularity break to me. (Plenty of C libraries I've used require explicit init calls).

Is it the use of "global variables"?
Or is it the use of the unsafePerformIO hack to create them?


The latter is definitely a problem.

The former, I'm not sure. My gut feeling is that it is, too.

Jules
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to