regions 0.3 → 0.4
raw patch · 6 files changed
+212/−94 lines, 6 filesdep ~MonadCatchIO-transformers
Dependency ranges changed: MonadCatchIO-transformers
Files
- Control/Monad/Trans/Region.hs +1/−1
- Control/Monad/Trans/Region/Internal.hs +32/−49
- Control/Monad/Trans/Region/Unsafe.hs +10/−20
- Control/Resource.hs +47/−0
- Data/RegionRef.hs +105/−0
- regions.cabal +17/−24
Control/Monad/Trans/Region.hs view
@@ -38,9 +38,9 @@ , ParentOf -- * Handy functions for writing monadic instances+ , liftCallCC , mapRegionT , liftCatch- -- | /TODO: define and export: /@liftCallCC@ ) where import Control.Monad.Trans.Region.Internal
Control/Monad/Trans/Region/Internal.hs view
@@ -4,7 +4,6 @@ , RankNTypes , ScopedTypeVariables , KindSignatures- , TypeFamilies , MultiParamTypeClasses , FunctionalDependencies , UndecidableInstances@@ -33,14 +32,8 @@ -------------------------------------------------------------------------------- module Control.Monad.Trans.Region.Internal- ( -- * Scarce resources- Resource- , Handle- , openResource- , closeResource-- -- * Regions- , RegionT+ ( -- * Regions+ RegionT -- * Running regions , runRegionT@@ -54,7 +47,6 @@ , RegionalHandle , internalHandle- , mapInternalHandle , open , with@@ -64,9 +56,9 @@ , dup -- * Handy functions for writing monadic instances+ , liftCallCC , mapRegionT , liftCatch- -- | /TODO: define and export: /@liftCallCC@ -- * Parent/child relationship between regions. , ParentOf@@ -99,33 +91,21 @@ -- from transformers: import Control.Monad.Trans ( MonadTrans, lift, MonadIO, liftIO ) -import qualified Control.Monad.Trans.Reader as Reader ( liftCatch )-import Control.Monad.Trans.Reader ( ReaderT- , ask- , runReaderT, mapReaderT- )+import qualified Control.Monad.Trans.Reader as R ( liftCallCC, liftCatch )+import Control.Monad.Trans.Reader ( ReaderT+ , ask+ , runReaderT, mapReaderT+ ) -- from base-unicode-symbols: import Data.Eq.Unicode ( (≡) ) import Data.Function.Unicode ( (∘) ) ------------------------------------------------------------------------------------- * Scarce resources-----------------------------------------------------------------------------------{-| Class of /scarce/ resources. A scarce resource is a resource that only one-user can use at a time. (like a file, memory pointer or USB device for-example).--Because of the scarcity, these resources need to be /opened/ to grant temporary-sole access to the resource. When the resource is no longer needed it should be-/closed/ a.s.a.p to grant others access to the resource.--}-class Resource resource where- data Handle resource ∷ *-- openResource ∷ resource → IO (Handle resource)- closeResource ∷ Handle resource → IO ()+-- from ourselves:+import Control.Resource ( Resource+ , Handle+ , openResource+ , closeResource+ ) --------------------------------------------------------------------------------@@ -186,14 +166,24 @@ {-| Get the reference count from the given regional handle. - Handles are reference counted because they may be /duplicated/- to a parent region using 'dup'.+ Normally a handle should be closed when its originating region+ terminates. There are two exceptions to this rule: + * When a handle is /duplicated/ to a parent region using 'dup'+ it should only be closed when the parent region terminates.++ * When a region is executed in a new thread using 'forkTopRegion' all+ handles that can be referenced in the originating region should also be+ referenceable in the new forked region. Therefore those handles should only be+ closed when the originating region or the new forked region terminates,+ whichever comes /last/.++ To implement this behaviour, handles are reference counted. The reference count is: * Initialized at 1 in 'open'. - * Incremented in 'dup'.+ * Incremented in 'dup' and 'forkTopRegion'. * Decremented on termination of 'runRegionWith' (which is called by 'runRegionT' and 'forkTopRegion').@@ -204,11 +194,6 @@ , refCntIORef ∷ IORef Int } --- | Modify the internal handle from the given regional handle.-mapInternalHandle ∷ (Handle resource1 → Handle resource2)- → (RegionalHandle resource1 r → RegionalHandle resource2 r)-mapInternalHandle f rh = rh { internalHandle = f $ internalHandle rh }- {-| Internally used function that atomically decrements the reference count that is stored in the given @IORef@. The function returns the decremented reference count.@@ -478,12 +463,10 @@ -- * Handy functions for writing monadic instances -------------------------------------------------------------------------------- --- TODO:--- -- | Lift a @callCC@ operation to the new monad.--- liftCallCC ∷ (((α → pr β) → pr α) → pr α) -- ^ @callCC@ on the argument monad.--- → ((α → RegionT s pr β) → RegionT s pr α)--- → RegionT s pr α--- liftCallCC callCC f = RegionT $ ???+-- | Lift a @callCC@ operation to the new monad.+liftCallCC ∷ (((α → pr β) → pr α) → pr α)+ → (((α → RegionT s pr β) → RegionT s pr α) → RegionT s pr α)+liftCallCC callCC f = RegionT $ R.liftCallCC callCC $ unRegionT ∘ f ∘ (RegionT ∘) -- | Transform the computation inside a region. mapRegionT ∷ (m α → n β) → RegionT s m α → RegionT s n β@@ -494,7 +477,7 @@ → 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)+liftCatch f m h = RegionT $ R.liftCatch f (unRegionT m) (unRegionT ∘ h) --------------------------------------------------------------------------------
Control/Monad/Trans/Region/Unsafe.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE UnicodeSyntax #-}+ ------------------------------------------------------------------------------- -- | -- Module : Control.Monad.Trans.Region.Unsafe@@ -10,29 +12,17 @@ -- 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.------ To create a module or library that allows your users to open your resources--- in a region, the only thing you have to do 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-- , internalHandle+ ( internalHandle , mapInternalHandle ) where -import Control.Monad.Trans.Region.Internal+import Control.Monad.Trans.Region.Internal ( RegionalHandle, internalHandle )+import Control.Resource ( Handle )++-- | Modify the internal handle from the given regional handle.+mapInternalHandle ∷ (Handle resource1 → Handle resource2)+ → (RegionalHandle resource1 r → RegionalHandle resource2 r)+mapInternalHandle f rh = rh { internalHandle = f $ internalHandle rh }
+ Control/Resource.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE UnicodeSyntax, NoImplicitPrelude, TypeFamilies #-}++-------------------------------------------------------------------------------+-- |+-- Module : Control.Resource+-- Copyright : (c) 2009 Bas van Dijk+-- License : BSD3 (see the file LICENSE)+-- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com>+--+-- Unsafely opening and closing of scarce resources.+--+--------------------------------------------------------------------------------++module Control.Resource+ ( Resource+ , Handle+ , openResource+ , closeResource+ ) where++import System.IO ( IO )++{-| Class of /scarce/ resources. A scarce resource is a resource that only one+user can use at a time. (like a file, memory pointer or USB device for+example).++Because of the scarcity, these resources need to be /opened/ to grant temporary+sole access to the resource. When the resource is no longer needed it should be+/closed/ a.s.a.p to grant others access to the resource.+-}+class Resource resource where+ data Handle resource ∷ *++ -- | Yield an @IO@ computation that opens the given resource and returns a+ -- @Handle@ on it.+ --+ -- Think of a handle as your private session with the resource. As long as+ -- you have it, other users can't use the resource. So don't forget to close+ -- this session with the resource as soon as you're done with it.+ openResource ∷ resource → IO (Handle resource)++ -- | Yield an @IO@ computation that closes the resource identified by the+ -- given @Handle@.+ --+ -- /Warning/: Using the @Handle@ after the resource has been closed will+ -- usually throw an exception or result in a program crash!+ closeResource ∷ Handle resource → IO ()
+ Data/RegionRef.hs view
@@ -0,0 +1,105 @@+{-# LANGUAGE UnicodeSyntax, NoImplicitPrelude, KindSignatures #-}++-------------------------------------------------------------------------------+-- |+-- Module : Data.RegionRef+-- Copyright : (c) 2009 Bas van Dijk+-- License : BSD3 (see the file LICENSE)+-- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com>+--+-- A mutable variable in the region monad that should provide a safer+-- replacement for an 'IORef' because you can't use it outside the region in+-- which it was created (unless you explicitly duplicate it).+--+--------------------------------------------------------------------------------++module Data.RegionRef+ ( RegionRef+ , pureDup+ , newRegionRef+ , readRegionRef+ , writeRegionRef+ , modifyRegionRef+ , atomicModifyRegionRef+ ) where++--------------------------------------------------------------------------------+-- Imports+--------------------------------------------------------------------------------++-- from base:+import Data.Function ( ($) )+import Control.Monad ( liftM )+import Data.Eq ( Eq )+import Data.IORef ( IORef+ , newIORef+ , readIORef, writeIORef+ , modifyIORef, atomicModifyIORef+ )++-- from base-unicode-symbols:+import Data.Function.Unicode ( (∘) )++-- from transformers:+import Control.Monad.Trans ( MonadIO, liftIO )++-- from ourselves:+import Control.Monad.Trans.Region ( RegionT, ParentOf )+++--------------------------------------------------------------------------------+-- Mutable references in the region monad+--------------------------------------------------------------------------------++-- | A mutable variable storing a value of type @α@ which can only be used+-- in region @r@, @r@'s children or @r@'s parent when you duplicate it using+-- 'pureDup'.+newtype RegionRef (r ∷ * → *) α = RegionRef { unRegionRef ∷ IORef α }+ deriving ( Eq )++-- | Transform the region type @r@ of the regional reference to @r@'s parent so+-- that it can be used in that region.+pureDup ∷ RegionRef (RegionT cs (RegionT ps ppr)) α+ → RegionRef (RegionT ps ppr) α+pureDup = RegionRef ∘ unRegionRef++{-| Yield a regional computation that returns a new regional reference that+stores the given value.++Note that the reference is parameterized by the same region in which it was+created. This ensures you can never use this reference outside that region and+it allows you to use this reference in a child region of that region+-}+newRegionRef ∷ MonadIO pr+ ⇒ α → RegionT s pr (RegionRef (RegionT s pr) α)+newRegionRef = liftM RegionRef ∘ liftIO ∘ newIORef++-- | Read the value of the given regional reference.+readRegionRef ∷ (pr `ParentOf` cr, MonadIO cr)+ ⇒ RegionRef pr α → cr α+readRegionRef = liftIO ∘ readIORef ∘ unRegionRef++-- | Write a new value into the given regional reference.+writeRegionRef ∷ (pr `ParentOf` cr, MonadIO cr)+ ⇒ RegionRef pr α → α → cr ()+writeRegionRef ref x = liftIO $ writeIORef (unRegionRef ref) x++-- | Mutate the contents of the given regional reference using the given+-- function.+modifyRegionRef ∷ (pr `ParentOf` cr, MonadIO cr)+ ⇒ RegionRef pr α → (α → α) → cr ()+modifyRegionRef ref f = liftIO $ modifyIORef (unRegionRef ref) f++{-| Atomically modifies the contents of the given regional reference using the+given function.++This function is useful for using a regional reference in a safe way in a+multithreaded program. If you only have one regional reference, then using+@atomicModifyRegionRef@ to access and modify it will prevent race conditions.+-}+atomicModifyRegionRef ∷ (pr `ParentOf` cr, MonadIO cr)+ ⇒ RegionRef pr α → (α → (α, β)) → cr β+atomicModifyRegionRef ref f = liftIO $ atomicModifyIORef (unRegionRef ref) f+++-- The End ---------------------------------------------------------------------
regions.cabal view
@@ -1,10 +1,10 @@ name: regions-version: 0.3+version: 0.4 cabal-version: >=1.6 build-type: Simple license: BSD3 license-file: LICENSE-copyright: 2009 Bas van Dijk+copyright: 2010 Bas van Dijk author: Bas van Dijk maintainer: Bas van Dijk <v.dijk.bas@gmail.com> stability: experimental@@ -31,28 +31,19 @@ . - This package provides two modules:-- .-- * @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!-- .-- * @Control.Monad.Trans.Region@ provides the public and safe interface to- regions which can be used by end-users.+ Also see the @regions-monadsfd@ and @regions-monadstf@ packages which provide+ instances for the classes in the respected monads packages. . - Also see the @regions-monadsfd@ and @regions-monadstf@ packages which provide- instances for the classes in the respected monads packages.+ For an example on how to use this library see the @safer-file-handles@,+ @usb-safe@ or @regional-pointers@ packages. . - For an example of how to use this library see the @safer-file-handles@ or- @usb-safe@ packages.+ Note that if you want to open /your/ type of scarce resource in a region, the+ only thing you have to do is define an instance for the @Resource@ class+ (which you can find in: @Control.Resource@). source-repository head Type: darcs@@ -60,10 +51,12 @@ Library GHC-Options: -Wall- build-depends: base >= 4 && < 4.3- , base-unicode-symbols >= 0.1.1 && < 0.2- , transformers >= 0.1.4 && < 0.2- , MonadCatchIO-transformers == 0.0.2.*- exposed-modules: Control.Monad.Trans.Region- , Control.Monad.Trans.Region.Unsafe+ build-depends: base >= 4 && < 4.3+ , base-unicode-symbols >= 0.1.1 && < 0.2+ , transformers >= 0.1.4 && < 0.2+ , MonadCatchIO-transformers >= 0.0.2.0 && < 0.1+ exposed-modules: Control.Resource+ Control.Monad.Trans.Region+ Control.Monad.Trans.Region.Unsafe+ Data.RegionRef other-modules: Control.Monad.Trans.Region.Internal