This page is meant to contain discussion about global state and "things with identity". It's a companion to Adrian's http://www.haskell.org/hawiki/GlobalMutableState, but that's in the old Wiki, so I thought it better to start a new page.
See also Ian Stark's ACIO message http://www.haskell.org/pipermail/haskell-cafe/2004-November/007664.html.
As Brian Hulley put it, at the moment, there is a strange unnatural discrepancy between the fixed set of built-in privileged operations such as Data.Unique.newUnique which are "allowed" to make use of global state, and user defined operations which have to rely on a shaky hack in order to preserve natural abstraction barriers between components such as a user-defined Unique, Atom, and anything involving memoisation or device management etc.
The kind of applications we have in mind are:
- A source of random numbers, or of unique numbers. This should be on a per-thread basis.
- The value of 'stdin' or 'stdout'. We don't want to mutate this, but we might want to set the value for sub-computations, including any spawned threads.
A straw man
Here's a straw-man proposal.
- New top-level declaration to allocate a new key
key rng :: Key StdGen
A key is globally unique in a program. It supports equality but not ordering.
- You can read and write global state and local state:
readLS, readGS :: Key a -> IO a writeLS, writeGS :: Key a -> a -> IO a
The distinction between the two is that there is one global state, shared between all threads, but each thread has its own local state. One way to think of it would be to imagine that each thread has its own finite mapping from keys to values.
- We probably want to provide efficient finite maps on keys.
- Keys are useful independent of mutability. For example, GHC has lots of code going
thenIdKey = mkPreludeIdKey 3 returnIdName = mkPreludeIdKey 4
etc, where we hand out unique identifiers by hand. Easy to screw up.
- When you forkIO a thread, what (if anything) does the forked thread inherit?