global-variables-1.0: Namespaced, global, and top-level mutable variables without unsafePerformIO.

Data.Global

Contents

Description

Data.Global provides a global namespace of IORefs, MVars and TVars. This namespace may be accessed in pure code. Yet reading and writing to those IORefs, MVars and TVars happens still in their respective monads.

Data.Global is designed to meet the following use cases:

  • Simplify the declaration of top-level mutable variables, by avoiding any pragmas as well as unsafePerformIO.
  • Avoid having to pass references explicitly throughout the program in order to let distant parts communicate.
  • Enable a communication by convention scheme, where e.g. different libraries may communicate without code dependencies.
  • Simplify the configuration problem - at least for code in the IO monad.

Note, that this library does not encourage sloppy software design by re-introducing all bad effects of global variables. Nevertheless, sometimes global variables are a suitable solution to a problem. In that case Data.Global simplifies and extends their handling significantly.

Synopsis

Introductory Example

The most simple usage of Data.Global is as follows:

Let there be an IORef!

>>> let ref = declareIORef \"some-cool-variable\" 17

Use ref like any other IORef.

>>> readIORef ref
17

You can do the same with MVars and TVars.

The Namespace of Global Variables

The types of variables: IORef a, MVar a, and TVar a create separate namespaces. I.e. A variable of type IORef Int and one of type MVar Int can both exist with the same name.

Initialization

References / variables returned by any of the declare... functions are initialized as needed with the value provided to declare.... Have a look at this example.

 someVar1, someVar2 :: IORef Int
 someVar1 = declareIORef "my-global-var" 0
 someVar2 = declareIORef "my-global-var" 1

someVar1 and someVar2 are guaranteed to always denote the exact same IORef, but it is unspecified whether the first read access to that IORef returns 0 or 1. It can even have any other initial value if it is also accessed from some other part of the program.

Reference of Variable Declaration Functions

declareIORefSource

Arguments

:: Typeable a 
=> String

The identifying name

-> a

The initial value of the IORef, it may or may not be used.

-> IORef a

A unique IORef determined by (name, typeOf val). Whether it refers to the given initial value or not is unspecified.

declareIORef name val maps a variable name to an IORef. Calling it multiple times with the same name and type of val will always return the same IORef.

 someVar :: IORef Int
 someVar = declareMVar "my-global-some-var" 0

Note, there is no need to use unsafePerformIO or to add a {-# NOINLINE someVar #-} pragma in order to define top-level IORefs.

declareMVarSource

Arguments

:: Typeable a 
=> String

The identifying name

-> a

The initial value of the MVar, it may or may not be used.

-> MVar a

A unique MVar determined by (name, typeOf val). Whether it refers to the given initial value or not is unspecified.

declareMVar name val maps a variable name to an MVar. Calling it multiple times with the same name and type of val will always return the same MVar.

 someVar :: MVar Int
 someVar = declareMVar "my-global-some-var" 0

Note, there is no need to use unsafePerformIO or to add a {-# NOINLINE someVar #-} pragma in order to define top-level MVars.

declareTVarSource

Arguments

:: Typeable a 
=> String

The identifying name

-> a

The initial value of the TVar, it may or may not be used.

-> TVar a

A unique TVar determined by (name, typeOf val). Whether it refers to the given initial value or not is unspecified.

declareTVar name val maps a variable name to an TVar. Calling it multiple times with the same name and type of val will always return the same TVar.

 someVar :: TVar Int
 someVar = declareMVar "my-global-some-var" 0

Note, there is no need to use unsafePerformIO or to add a {-# NOINLINE someVar #-} pragma in order to define top-level TVars.