-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Pure structures that can be incrementally created in impure code -- -- This package provides a type class for incrementally creating pure -- structures in impure code. Also included is a queue with a pure front -- and an impure back. @package procrastinating-structure @version 1.0 -- | 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
--   
module Data.PVar.Structure -- | 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. class Structure a where { type family Constructor a; data family PStructure a; type family Inner a; } newStruc :: (Structure a) => IO (PStructure a, a) writeStruc :: (Structure a) => PStructure a -> Constructor a -> IO (Inner a) -- | Write the constructor for a structure with only one possible -- structure, assuming that the Constructor type for that type is -- (). writeSoleCon :: (Structure a, (Constructor a) ~ ()) => PStructure a -> IO (Inner a) -- | 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. newtype Value a Value :: a -> Value a getValue :: Value a -> a -- | Constructors for the Maybe instance. data MaybeC NothingC :: MaybeC JustC :: MaybeC -- | Constructors for the Either instance. data EitherC LeftC :: EitherC RightC :: EitherC -- | Constructors for the list instance. data ListC NilC :: ListC ConsC :: ListC instance (Structure a) => Structure [a] instance (Structure a, Structure b) => Structure (Either a b) instance (Structure a) => Structure (Maybe a) instance (Structure a, Structure b, Structure c, Structure d, Structure e, Structure f) => Structure (a, b, c, d, e, f) instance (Structure a, Structure b, Structure c, Structure d, Structure e) => Structure (a, b, c, d, e) instance (Structure a, Structure b, Structure c, Structure d) => Structure (a, b, c, d) instance (Structure a, Structure b, Structure c) => Structure (a, b, c) instance (Structure a, Structure b) => Structure (a, b) instance Structure () instance Structure (Value a) -- | A procrastinating queue. You can populate the back of the queue in IO -- and read the front of the queue in pure code. The front of an empty, -- unclosed queue is _|_. I think it fits the definition -- of referentially transparent, but it's still an abomination. It's -- possible to do some really stupid things with one of these -- Queues. If you read the source, this serves as an example of -- using Data.PVar.Structure. Here's a simple example of using a -- Queue: -- --
--   import Prelude hiding (sum)
--   import Data.Foldable (sum)
--   
--   main :: IO ()
--   main = do
--     (back, front) <- newQueue  -- Create a new queue.
--     mapM_ (push back) [0..9]   -- Push some values to the back of the queue.
--     print $ peek front         -- Safe to do since we know something has been written
--     close back                 -- Close the queue.
--     print $ sum front          -- Safe to do since the queue is finalized
--   
-- -- The output of the above program is: -- --
--   Just 0
--   45
--   
-- -- Is this useful? Who knows? It was a fun exercise. module Data.PVar.Queue -- | A pure queue. data Queue a -- | The impure back of a pure queue. data QueueBack a -- | Create both ends of a procrastinating queue. newQueue :: IO (QueueBack a, Queue a) -- | Push to the back of an open QueueBack. If the QueueBack -- has been closed, returns False. push :: QueueBack a -> a -> IO Bool -- | Close a QueueBack. This finalizes the Queue and means -- that it is safe to evaluate all the way to the end. close :: QueueBack a -> IO () -- | Get the value at the front of a Queue and return the remainder -- of the Queue. Returns False if we are at the end of a -- closed Queue. pop :: Queue a -> Maybe (Queue a, a) -- | Get the value at the front of a Queue. Returns False if -- we are at the end of a closed Queue. peek :: Queue a -> Maybe a instance Eq (QueueBack a) instance Functor Queue instance Applicative Queue instance Monad Queue instance MonadPlus Queue instance Alternative Queue instance Foldable Queue instance Traversable Queue instance (Eq a) => Eq (Queue a) instance (Ord a) => Ord (Queue a) instance Monoid (Queue a)