procrastinating-structure-1.0.1: Pure structures that can be incrementally created in impure code



This module provides the Structure type class, enabling you to create a pure data structure, which is available immediately, and then gradually fill it in using the IO monad. This means that you can go ahead and start using the structure before it is fully defined. If a part of the structure is evaluated before it has been written then that part is treated as _|_. This is technically more pure than values from unsafeInterleaveIO. Evaluating the structure, even before it is defined, doesn't perform any IO. All the IO happens in the IO monad.

Here is an example of creating a list of Ints and then writing each level of it step by step. The returned result is [5].

 foo :: IO [Int]
 foo = do

   -- Create the pure list and the handle for writing to it.
   (pxs, xs) <- newStruc

   -- Write the cons constructor to the list. This gives us handles
   -- for writing the head and tail of the list.
   Just (h, t) <- writeStruc pxs ConsC

   -- Write the head of the list.
   writeStruc h 5

   -- Write the tail of the list. This finishes it.
   writeStruc t NilC

   -- Get rid of the Value wrapper on the list's value and return
   -- the resulting list.
   return $ map getValue xs



class Structure a whereSource

A structure type is one which represents any lazy data structure. With the exception of the Value newtype wrapper, there is little reason to define an instance of Structure for completely strict types. This is because the entire thing must be defined at once anyway, so you might as well just use a PVar.

Associated Types

type Constructor a Source

A type representing the structure's constructors by themselves along with any strict data to go along with the head of the structure.

data PStructure a Source

The internal representation of the handle for writing values in IO.

type Inner a Source

The result type from writing the head of the structure. This is to access deeper levels of the structure.


newStruc :: IO (PStructure a, a)Source

Create a new structure and a handle for writing to it.

writeStruc :: PStructure a -> Constructor a -> IO (Inner a)Source

Write the specified constructor to the given handle and return whatever other handles are necessary to write deeper levels of the structure.


Structure () 
Structure a => Structure [a] 
Structure a => Structure (Maybe a) 
Structure (Value a) 
(Structure a, Structure b) => Structure (Either a b) 
(Structure a, Structure b) => Structure (a, b) 
(Structure a, Structure b, Structure c) => Structure (a, b, c) 
(Structure a, Structure b, Structure c, Structure d) => Structure (a, b, c, d) 
(Structure a, Structure b, Structure c, Structure d, Structure e) => Structure (a, b, c, d, e) 
(Structure a, Structure b, Structure c, Structure d, Structure e, Structure f) => Structure (a, b, c, d, e, f) 

writeSoleCon :: (Structure a, Constructor a ~ ()) => PStructure a -> IO (Inner a)Source

Write the constructor for a structure with only one possible structure, assuming that the Constructor type for that type is ().

newtype Value a Source

Treat the wrapped value as an atomic structure. This has the same effect as a PVar, but allows you to use the Structure interface. This is also necessary for the leaves of most structures.




getValue :: a


data MaybeC Source

Constructors for the Maybe instance.



data EitherC Source

Constructors for the Either instance.



data ListC Source

Constructors for the list instance.