Difference between revisions of "Global keys"

From HaskellWiki
Jump to navigation Jump to search
Line 25: Line 25:
 
readLS, readGS :: Key a -> IO a
 
readLS, readGS :: Key a -> IO a
 
writeLS, writeGS :: Key a -> a -> IO a
 
writeLS, writeGS :: Key a -> a -> IO a
</haskell> The distinction between the two is that there is one global state, shared between all threads, but each thread has its own local state.
+
</haskell> 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.
* Keys have equality but not ordering. We probably want to provide efficient finite maps on keys.
+
* We probably want to provide efficient finite maps on keys.
  +
* Keys are useful independent of mutability. For example, GHC has lots of code going
  +
<haskell>
  +
thenIdKey = mkPreludeIdKey 3
  +
returnIdName = mkPreludeIdKey 4
  +
</haskell>
  +
etc, where we hand out unique identifiers by hand. Easy to screw up.
   
 
Open questions:
 
Open questions:

Revision as of 16:36, 4 May 2006

Introduction

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.

Examples

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.

Open questions:

  • When you forkIO a thread, what (if anything) does the forked thread inherit?