packages feed

regions 0.1.0.1 → 0.2

raw patch · 4 files changed

+128/−94 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Control.Monad.Trans.Region.Internal: class (Resource resource) => Dup α resource
- Control.Monad.Trans.Region.Internal: class (Monad pr, Monad cr) => ParentOf pr cr
- Control.Monad.Trans.Region.Internal: class Resource resource where { data family Handle resource :: *; }
- Control.Monad.Trans.Region.Internal: closeResource :: (Resource resource) => Handle resource -> IO ()
- Control.Monad.Trans.Region.Internal: data RegionT resource s pr :: (* -> *) α
- Control.Monad.Trans.Region.Internal: data RegionalHandle resource r :: (* -> *)
- Control.Monad.Trans.Region.Internal: dup :: (Dup α resource, MonadCatchIO ppr) => α (RegionT resource cs (RegionT resource ps ppr)) -> RegionT resource cs (RegionT resource ps ppr) (α (RegionT resource ps ppr))
- Control.Monad.Trans.Region.Internal: forkTopRegion :: (Resource resource, MonadIO pr) => TopRegion resource s () -> RegionT resource s pr ThreadId
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (Alternative pr) => Alternative (RegionT resource s pr)
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (Applicative pr) => Applicative (RegionT resource s pr)
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (Functor pr) => Functor (RegionT resource s pr)
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (Monad cr, TypeCast2 cr (RegionT resource s pcr), ParentOf pr pcr) => ParentOf pr cr
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (Monad pr) => Monad (RegionT resource s pr)
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (Monad r) => ParentOf r r
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (MonadCatchIO pr) => MonadCatchIO (RegionT resource s pr)
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (MonadFix pr) => MonadFix (RegionT resource s pr)
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (MonadIO pr) => MonadIO (RegionT resource s pr)
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (MonadPlus pr) => MonadPlus (RegionT resource s pr)
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (Resource resource) => Dup (RegionalHandle resource) resource
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (TypeCast2' () a b) => TypeCast2 a b
- Control.Monad.Trans.Region.Internal: instance [overlap ok] (TypeCast2'' t a b) => TypeCast2' t a b
- Control.Monad.Trans.Region.Internal: instance [overlap ok] MonadTrans (RegionT resource s)
- Control.Monad.Trans.Region.Internal: instance [overlap ok] TypeCast2'' () a a
- Control.Monad.Trans.Region.Internal: internalHandle :: RegionalHandle resource r -> Handle resource
- Control.Monad.Trans.Region.Internal: liftCatch :: (pr α -> (e -> pr α) -> pr α) -> RegionT resource s pr α -> (e -> RegionT resource s pr α) -> RegionT resource s pr α
- Control.Monad.Trans.Region.Internal: mapRegionT :: (m α -> n β) -> RegionT resource s m α -> RegionT resource s n β
- Control.Monad.Trans.Region.Internal: open :: (Resource resource, MonadCatchIO pr) => resource -> RegionT resource s pr (RegionalHandle resource (RegionT resource s pr))
- Control.Monad.Trans.Region.Internal: openResource :: (Resource resource) => resource -> IO (Handle resource)
- Control.Monad.Trans.Region.Internal: runRegionT :: (Resource resource, MonadCatchIO pr) => (forall s. RegionT resource s pr α) -> pr α
- Control.Monad.Trans.Region.Internal: runTopRegion :: (Resource resource) => (forall s. TopRegion resource s α) -> IO α
- Control.Monad.Trans.Region.Internal: type TopRegion resource s = RegionT resource s IO
- Control.Monad.Trans.Region.Internal: with :: (Resource resource, MonadCatchIO pr) => resource -> (forall s. RegionalHandle resource (RegionT resource s pr) -> RegionT resource s pr α) -> pr α
+ Control.Monad.Trans.Region: liftCatch :: (pr α -> (e -> pr α) -> pr α) -> RegionT s pr α -> (e -> RegionT s pr α) -> RegionT s pr α
+ Control.Monad.Trans.Region: mapRegionT :: (m α -> n β) -> RegionT s m α -> RegionT s n β
+ Control.Monad.Trans.Region.Unsafe: class Dup α
+ Control.Monad.Trans.Region.Unsafe: class (Monad pr, Monad cr) => ParentOf pr cr
+ Control.Monad.Trans.Region.Unsafe: class Resource resource where { data family Handle resource :: *; }
+ Control.Monad.Trans.Region.Unsafe: closeResource :: (Resource resource) => Handle resource -> IO ()
+ Control.Monad.Trans.Region.Unsafe: dup :: (Dup α, MonadCatchIO ppr) => α (RegionT cs (RegionT ps ppr)) -> RegionT cs (RegionT ps ppr) (α (RegionT ps ppr))
+ Control.Monad.Trans.Region.Unsafe: internalHandle :: RegionalHandle resource r -> Handle resource
+ Control.Monad.Trans.Region.Unsafe: openResource :: (Resource resource) => resource -> IO (Handle resource)
- Control.Monad.Trans.Region: data RegionT resource s pr :: (* -> *) α
+ Control.Monad.Trans.Region: data RegionT s pr :: (* -> *) α
- Control.Monad.Trans.Region: dup :: (Dup α resource, MonadCatchIO ppr) => α (RegionT resource cs (RegionT resource ps ppr)) -> RegionT resource cs (RegionT resource ps ppr) (α (RegionT resource ps ppr))
+ Control.Monad.Trans.Region: dup :: (Dup α, MonadCatchIO ppr) => α (RegionT cs (RegionT ps ppr)) -> RegionT cs (RegionT ps ppr) (α (RegionT ps ppr))
- Control.Monad.Trans.Region: forkTopRegion :: (Resource resource, MonadIO pr) => TopRegion resource s () -> RegionT resource s pr ThreadId
+ Control.Monad.Trans.Region: forkTopRegion :: (MonadIO pr) => TopRegion s () -> RegionT s pr ThreadId
- Control.Monad.Trans.Region: open :: (Resource resource, MonadCatchIO pr) => resource -> RegionT resource s pr (RegionalHandle resource (RegionT resource s pr))
+ Control.Monad.Trans.Region: open :: (Resource resource, MonadCatchIO pr) => resource -> RegionT s pr (RegionalHandle resource (RegionT s pr))
- Control.Monad.Trans.Region: runRegionT :: (Resource resource, MonadCatchIO pr) => (forall s. RegionT resource s pr α) -> pr α
+ Control.Monad.Trans.Region: runRegionT :: (MonadCatchIO pr) => (forall s. RegionT s pr α) -> pr α
- Control.Monad.Trans.Region: runTopRegion :: (Resource resource) => (forall s. TopRegion resource s α) -> IO α
+ Control.Monad.Trans.Region: runTopRegion :: (forall s. TopRegion s α) -> IO α
- Control.Monad.Trans.Region: type TopRegion resource s = RegionT resource s IO
+ Control.Monad.Trans.Region: type TopRegion s = RegionT s IO
- Control.Monad.Trans.Region: with :: (Resource resource, MonadCatchIO pr) => resource -> (forall s. RegionalHandle resource (RegionT resource s pr) -> RegionT resource s pr α) -> pr α
+ Control.Monad.Trans.Region: with :: (Resource resource, MonadCatchIO pr) => resource -> (forall s. RegionalHandle resource (RegionT s pr) -> RegionT s pr α) -> pr α

Files

Control/Monad/Trans/Region.hs view
@@ -32,6 +32,11 @@        -- * Duplication     , dup++      -- * Handy functions for writing monadic instances+    , mapRegionT+    , liftCatch+      -- | /TODO: define and export: /@liftCallCC@     ) where  import Control.Monad.Trans.Region.Internal
Control/Monad/Trans/Region/Internal.hs view
@@ -11,6 +11,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverlappingInstances #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE ExistentialQuantification #-}  ------------------------------------------------------------------------------- -- |@@ -24,17 +25,8 @@ -- -- See: <http://okmij.org/ftp/Haskell/regions.html#light-weight> ----- This module should only be used by library authors wishing to allow their--- users to open their type of resources in a region. It should not be used by--- end-users directly!------ To create a module or library that allows your users to open your type of--- resources in a region is to define an instance for 'Resource' for your type--- of resource.------ Make sure not to re-export anything from this module. Either re-export things--- from @Control.Monad.Trans.Region@ or tell your users to import that module--- directly.+-- This is an internal module not intended to be exported.+-- Use @Control.Monad.Trans.Region@  or @Control.Monad.Trans.Region.Unsafe@. -- -------------------------------------------------------------------------------- @@ -85,7 +77,7 @@ import Control.Concurrent  ( forkIO, ThreadId ) import Control.Applicative ( Applicative, Alternative ) import Control.Monad       ( Monad, return, (>>=), fail-                           , (>>), when, liftM2, mapM_+                           , (>>), when, liftM2, mapM_, forM_                            , Functor                            , MonadPlus                            )@@ -135,15 +127,15 @@ -- * Regions -------------------------------------------------------------------------------- -{-| A monad transformer in which resources of type @resource@ can be opened+{-| A monad transformer in which scarce resources can be opened which are automatically closed when the region terminates.  Note that regions can be nested. @pr@ (for parent region) is a monad which is usually the region which is running this region. However when you are running a 'TopRegion' the parent region will be 'IO'. -}-newtype RegionT resource s (pr ∷ * → *) α = RegionT-    { unRegionT :: ReaderT (IORef [Opened resource]) pr α }+newtype RegionT s (pr ∷ * → *) α = RegionT+    { unRegionT ∷ ReaderT (IORef [SomeOpenedResource]) pr α }      deriving ( Functor              , Applicative@@ -156,10 +148,19 @@              , MonadCatchIO              ) -{-| An @Opened resource@ is an internal data type which associates a handle to-the resource with a reference count. Handles are reference counted because they-may be /duplicated/ to a parent region using 'dup'.+-- | An internally used datatype which adds an existential wrapper around+-- 'OpenedResource' to hide the @resource@ type. If the @resource@ type is not+-- hidden, regions must be parameterized by it. This is undesirable because then+-- only one type of resource can be opened in a region. The following allows all+-- kinds of resources to be opened in a single region as long as they have an+-- instance for 'Resource'.+data SomeOpenedResource = ∀ resource. Resource resource+                        ⇒ Some (Opened resource) +{-| An @Opened resource@ is an internally used data type which associates a+handle to the resource with a reference count. Handles are reference counted+because they may be /duplicated/ to a parent region using 'dup'.+ The reference count is:   * Initialized at 1 in 'open'.@@ -175,16 +176,17 @@                               , refCntIORef  ∷ IORef Int                               } --- | Internal function that atomically decrements the reference count that is--- stored in the given @IORef@. The function returns the decremented reference--- count.+{-| Internally used function that atomically decrements the reference count that+is stored in the given @IORef@. The function returns the decremented reference+count.+-} decrement ∷ IORef Int → IO Int decrement ioRef = atomicModifyIORef ioRef $ \refCnt →                   let predRefCnt = pred refCnt                   in (predRefCnt, predRefCnt) --- | Internal function that atomically increments the reference count that is--- stored in the given @IORef@.+-- | Internally used function that atomically increments the reference count that+-- is stored in the given @IORef@. increment ∷ IORef Int → IO () increment ioRef = atomicModifyIORef ioRef $ \refCnt →                   (succ refCnt, ())@@ -216,10 +218,7 @@  Note that it is possible to run a region inside another region. -}-runRegionT ∷ (Resource resource, MonadCatchIO pr)-           ⇒ (∀ s. RegionT resource s pr α) -- ^ Region you wish to execute.-           → pr α -- ^ Computation in the parent region which executes the given-                  --   region.+runRegionT ∷ MonadCatchIO pr ⇒ (∀ s. RegionT s pr α) → pr α runRegionT m = runRegionWith [] m  {-| A region which has 'IO' as its parent region which enables it to be:@@ -228,16 +227,13 @@   * concurrently executed in a new thread by 'forkTopRegion'. -}-type TopRegion resource s = RegionT resource s IO+type TopRegion s = RegionT s IO  {-| Convenience funtion for running a /top-level/ region in 'IO'.  Note that: @runTopRegion = 'runRegionT'@ -}-runTopRegion ∷ Resource resource-             ⇒ (∀ s. TopRegion resource s α)-                    -- ^ /Top-level/ region you wish to execute.-             → IO α -- ^ An @IO@ computation which executes the given region.+runTopRegion ∷ (∀ s. TopRegion s α) → IO α runTopRegion = runRegionT  {-| Return a region which executes the given /top-level/ region in a new thread.@@ -260,12 +256,7 @@ thread are closed only when the current thread or the forked thread terminates whichever comes /last/. -}-forkTopRegion ∷ (Resource resource, MonadIO pr)-              ⇒ TopRegion resource s () -- ^ /Top-level/ region you wish to-                                        --   execute in a new thread.-              → RegionT resource s pr ThreadId-                -- ^ A regional computation that executes the given region in a-                --   new thread and returns the @ThreadId@ of this new thread.+forkTopRegion ∷ MonadIO pr ⇒ TopRegion s () → RegionT s pr ThreadId forkTopRegion m = RegionT $ do   -- Get the list of currently opened resources in this region:   openedResourcesIORef ← ask@@ -275,7 +266,8 @@                 -- Increment the reference count of each opened resource so that                 -- when the current region terminates the resources will stay                 -- open in the to be created thread:-                mapM_ (increment ∘ refCntIORef) openedResources+                forM_ openedResources $ \(Some openedResource) →+                  increment $ refCntIORef $ openedResource                  -- Fork a new thread that will concurrently run the given region                 -- on the opened resources of the current region:@@ -289,12 +281,11 @@                 -- count will never reach 0!)                 forkIO $ runRegionWith openedResources m --- | Internal function that actually runs the region on the given list of opened--- resources.-runRegionWith ∷ ∀ resource s pr α.-                (MonadCatchIO pr, Resource resource)-              ⇒ [Opened resource]-              → RegionT resource s pr α+-- | Internally used function that actually runs the region on the given list of+-- opened resources.+runRegionWith ∷ ∀ s pr α. MonadCatchIO pr+              ⇒ [SomeOpenedResource]+              → RegionT s pr α               → pr α runRegionWith openedResources m =     bracket@@ -310,7 +301,7 @@        (runReaderT $ unRegionT m)     where-      end (Opened {openedHandle, refCntIORef}) = do+      end (Some (Opened {openedHandle, refCntIORef})) = do         refCnt ← decrement refCntIORef         when (refCnt ≡ 0) $ closeResource openedHandle @@ -326,8 +317,9 @@  {-| Get the internal handle from the regional handle. -/Warning:/ This function should not be exported to end-users because it allows-them to close the handle manually!+/Warning:/ This function should not be exported to or used by end-users because+it allows them to close the handle manually, which will defeat the+safety-guarantees that this package provides!  /Tip:/ If you enable the @ViewPatterns@ language extension you can use @internalHandle@ as a view-pattern as in the following example from the@@ -353,11 +345,9 @@ it was created you have to /duplicate/ the handle by applying 'dup' to it. -} open ∷ (Resource resource, MonadCatchIO pr)-     ⇒ resource -- ^ The resource you wish to open.-     → RegionT resource s pr-         (RegionalHandle resource (RegionT resource s pr))-         -- ^ A regional computation that returns a regional handle to the given-         --   opened resource parameterized by the region itself.+     ⇒ resource+     → RegionT s pr+         (RegionalHandle resource (RegionT s pr)) open resource = block $ do   -- Create a new opened resource by actually opening the resource and   -- intializing the reference count to 1:@@ -385,23 +375,17 @@ Note that: @with dev f = @'runRegionT'@ (@'open'@ dev @'>>='@ f)@ -} with ∷ (Resource resource, MonadCatchIO pr)-     ⇒ resource -- ^ The resource you wish to open.-     → (∀ s. RegionalHandle resource (RegionT resource s pr)-           → RegionT resource s pr α-       ) -- ^ Continuation function.-     → pr α -- ^ A computation which runs a child region which opens the given-            --   resource and applies the given continuation function to the-            --   resulting regional handle.+     ⇒ resource+     → (∀ s. RegionalHandle resource (RegionT s pr) → RegionT s pr α)+     → pr α with resource f = runRegionT $ open resource >>= f --- | Internal function to /register/ the given opened resource by consing it to--- the list of opened resources of the region.-register ∷ (Resource resource, MonadIO pr)-         ⇒ Opened resource-         → RegionT resource s pr ()+-- | Internally used function to /register/ the given opened resource by consing+-- it to the list of opened resources of the region.+register ∷ (Resource resource, MonadIO pr) ⇒ Opened resource → RegionT s pr () register openedResource = RegionT $ do   openedResourcesIORef ← ask-  liftIO $ modifyIORef openedResourcesIORef (openedResource:)+  liftIO $ modifyIORef openedResourcesIORef (Some openedResource:)   --------------------------------------------------------------------------------@@ -432,12 +416,12 @@  ...yielding the regional handle @r1h@. Note that: -@r1h :: RegionalHandle resource (RegionT resource cs (RegionT resource ps ppr))@+@r1h :: RegionalHandle resource (RegionT cs (RegionT ps ppr))@  where @cs@ is bound by the inner (child) @runRegionT@ and @ps@ is bound by the outer (parent) @runRegionT@. -Suppose you want to use the resulting regional handle @r1h@ in the /parent/ device+Suppose you want to use the resulting regional handle @r1h@ in the /parent/ region. You can't simply @return r1h@ because then the type variable @cs@, escapes the inner region. @@ -448,20 +432,19 @@         return r1hDup @ -Note that @r1hDup :: RegionalHandle resource (RegionT resource ps ppr)@+Note that @r1hDup :: RegionalHandle resource (RegionT ps ppr)@  Back in the parent region you can safely operate on @r1hDup@. -}-class Resource resource ⇒ Dup α resource where-    dup ∷ (MonadCatchIO ppr)-        ⇒ α (RegionT resource cs (RegionT resource ps ppr))-          -- ^ Something created in a child region.-        → RegionT resource cs (RegionT resource ps ppr)-              (α (RegionT resource ps ppr))-          -- ^ The child region which returns the thing which can now be used in-          --   the parent region.+class Dup α where+    dup ∷ MonadCatchIO ppr+        ⇒ α (RegionT cs (RegionT ps ppr))+        → RegionT cs (RegionT ps ppr)+              (α (RegionT ps ppr))+          -- The child region which returns the thing which can now be used in+          -- the parent region. -instance Resource resource ⇒ Dup (RegionalHandle resource) resource where+instance Resource resource ⇒ Dup (RegionalHandle resource) where     dup (RegionalHandle openedResource) = block $ do       -- Increment the reference count of the given opened resource so that it       -- won't get closed when the current region terminates:@@ -495,14 +478,14 @@ -- liftCallCC callCC f = RegionT $ ???  -- | Transform the computation inside a region.-mapRegionT ∷ (m α → n β) → RegionT resource s m α → RegionT resource s n β+mapRegionT ∷ (m α → n β) → RegionT s m α → RegionT s n β mapRegionT f = RegionT ∘ mapReaderT f ∘ unRegionT  -- | Lift a 'catchError' operation to the new monad.-liftCatch ∷ (pr α → (e → pr α) → pr α)    -- ^ @catch@ on the argument monad.-          → RegionT resource s pr α       -- ^ Computation to attempt.-          → (e → RegionT resource s pr α) -- ^ Exception handler.-          → RegionT resource s pr α+liftCatch ∷ (pr α → (e → pr α) → pr α) -- ^ @catch@ on the argument monad.+          → RegionT s pr α             -- ^ Computation to attempt.+          → (e → RegionT s pr α)       -- ^ Exception handler.+          → RegionT s pr α liftCatch f m h = RegionT $ Reader.liftCatch f (unRegionT m) (unRegionT ∘ h)  @@ -515,16 +498,16 @@ A region is the parent of another region if they're either equivalent like:  @-RegionT resource ps pr  \`ParentOf\`  RegionT resource ps pr+RegionT ps pr  \`ParentOf\`  RegionT ps pr @  or if it is the parent of the parent of the child like:  @-RegionT resource ps ppr \`ParentOf\` RegionT resource cs-                                     (RegionT resource pcs-                                       (RegionT resource ppcs-                                         (RegionT resource ps ppr)))+RegionT ps ppr \`ParentOf\` RegionT cs+                              (RegionT pcs+                                (RegionT ppcs+                                  (RegionT ps ppr))) @ -} class (Monad pr, Monad cr) ⇒ pr `ParentOf` cr@@ -532,7 +515,7 @@ instance Monad r ⇒ ParentOf r r  instance ( Monad cr-         , cr `TypeCast2` RegionT resource s pcr+         , cr `TypeCast2` RegionT s pcr          , pr `ParentOf` pcr          )          ⇒ ParentOf pr cr
+ Control/Monad/Trans/Region/Unsafe.hs view
@@ -0,0 +1,44 @@+-------------------------------------------------------------------------------+-- |+-- Module      :  Control.Monad.Trans.Region.Unsafe+-- Copyright   :  (c) 2009 Bas van Dijk+-- License     :  BSD3 (see the file LICENSE)+-- Maintainer  :  Bas van Dijk <v.dijk.bas@gmail.com>+--+-- /WARNING:/ This module should /not/ be used by end-users directly because it+-- allows access to the 'internalHandle' of a resource which enables them to+-- close the resource manually, which will defeat the safety-guarantees that+-- this package provides!+--+-- This module should /only/ be used by library authors wishing to allow their+-- end-users to open their resources in a region.+--+-- The only thing to do, to create a module or library that allows your users to+-- open your resources in a region, is to define an instance for 'Resource' for+-- your type of resource.+--+-- Make sure not to re-export anything from this module. Either re-export things+-- from @Control.Monad.Trans.Region@ or tell your users to import that module+-- directly.+--+--------------------------------------------------------------------------------++module Control.Monad.Trans.Region.Unsafe+    ( -- * Scarce resources+      Resource+    , Handle+    , openResource+    , closeResource++      -- * Accessing the internal handle of a resource.+    , internalHandle++      -- * Duplication+    , Dup+    , dup++      -- * Parent/child relationship between regions.+    , ParentOf+    ) where++import Control.Monad.Trans.Region.Internal
regions.cabal view
@@ -1,5 +1,5 @@ name:          regions-version:       0.1.0.1+version:       0.2 cabal-version: >=1.6 build-type:    Simple license:       BSD3@@ -35,9 +35,9 @@    . -  * @Control.Monad.Trans.Region.Internal@ should only be used by library authors+  * @Control.Monad.Trans.Region.Unsafe@ should only be used by library authors     wishing to allow their users to open their type of resources in a region. It-    should not be used by end-users directly!+    should /not/ be used by end-users directly!    . @@ -51,7 +51,8 @@    . -  For an example of how to use this library see the @usb-safe@ package.+  For an example of how to use this library see the @safer-file-handles@ or+  @usb-safe@ packages.  source-repository head   Type:     darcs@@ -64,4 +65,5 @@                , transformers              >= 0.1.4 && < 0.2                , MonadCatchIO-transformers == 0.0.2.*   exposed-modules: Control.Monad.Trans.Region-                 , Control.Monad.Trans.Region.Internal+                 , Control.Monad.Trans.Region.Unsafe+  other-modules:   Control.Monad.Trans.Region.Internal